drawlib 0.1.1__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.
Potentially problematic release.
This version of drawlib might be problematic. Click here for more details.
- drawlib/.pylintrc +2 -0
- drawlib/__init__.py +33 -0
- drawlib/__main__.py +21 -0
- drawlib/apis.py +22 -0
- drawlib/assets/__init__.py +8 -0
- drawlib/assets/v0_1/__init__.py +8 -0
- drawlib/assets/v0_1/fonticons/__init__.py +8 -0
- drawlib/assets/v0_1/fonts/__init__.py +8 -0
- drawlib/v0_1/__init__.py +31 -0
- drawlib/v0_1/__main__.py +20 -0
- drawlib/v0_1/apis.py +127 -0
- drawlib/v0_1/private/__init__.py +20 -0
- drawlib/v0_1/private/arg_validator.py +163 -0
- drawlib/v0_1/private/command.py +204 -0
- drawlib/v0_1/private/core/__init__.py +15 -0
- drawlib/v0_1/private/core/colors.py +285 -0
- drawlib/v0_1/private/core/dimage.py +510 -0
- drawlib/v0_1/private/core/fonts.py +324 -0
- drawlib/v0_1/private/core/model.py +1082 -0
- drawlib/v0_1/private/core/model_validator.py +175 -0
- drawlib/v0_1/private/core/theme.py +1042 -0
- drawlib/v0_1/private/core/util.py +809 -0
- drawlib/v0_1/private/core_canvas/__init__.py +15 -0
- drawlib/v0_1/private/core_canvas/base.py +653 -0
- drawlib/v0_1/private/core_canvas/canvas.py +88 -0
- drawlib/v0_1/private/core_canvas/image.py +154 -0
- drawlib/v0_1/private/core_canvas/line.py +263 -0
- drawlib/v0_1/private/core_canvas/original_arrow.py +139 -0
- drawlib/v0_1/private/core_canvas/original_polygon.py +584 -0
- drawlib/v0_1/private/core_canvas/patches.py +547 -0
- drawlib/v0_1/private/core_canvas/text.py +136 -0
- drawlib/v0_1/private/download.py +58 -0
- drawlib/v0_1/private/dutil.py +28 -0
- drawlib/v0_1/private/icons/__init__.py +15 -0
- drawlib/v0_1/private/icons/phosphor.py +35275 -0
- drawlib/v0_1/private/icons/util.py +82 -0
- drawlib/v0_1/private/logging.py +38 -0
- drawlib/v0_1/private/settings.py +233 -0
- drawlib/v0_1/private/smartarts/__init__.py +15 -0
- drawlib/v0_1/private/smartarts/cycle.py +11 -0
- drawlib/v0_1/private/smartarts/dsart.py +17 -0
- drawlib/v0_1/private/smartarts/groups.py +20 -0
- drawlib/v0_1/private/smartarts/pyramid.py +18 -0
- drawlib/v0_1/private/smartarts/sourcecode.py +216 -0
- drawlib/v0_1/private/smartarts/table.py +11 -0
- drawlib/v0_1/private/smartarts/tree.py +18 -0
- drawlib/v0_1/private/tools.py +161 -0
- drawlib/v0_1/private/util.py +353 -0
- drawlib-0.1.1.dist-info/LICENSE.txt +202 -0
- drawlib-0.1.1.dist-info/METADATA +36 -0
- drawlib-0.1.1.dist-info/RECORD +52 -0
- drawlib-0.1.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
# Copyright (c) 2024 Yuichi Ito (yuichi@yuichi.com)
|
|
2
|
+
#
|
|
3
|
+
# This software is licensed under the Apache License, Version 2.0.
|
|
4
|
+
# For more information, please visit: https://github.com/yuichi110/drawlib
|
|
5
|
+
#
|
|
6
|
+
# This software is provided "as is", without warranty of any kind,
|
|
7
|
+
# express or implied, including but not limited to the warranties of
|
|
8
|
+
# merchantability, fitness for a particular purpose and noninfringement.
|
|
9
|
+
|
|
10
|
+
"""drawlib image class
|
|
11
|
+
|
|
12
|
+
drawlib depends on ``PIL.Image.Image`` for drawing image.
|
|
13
|
+
It is very useful and easy to use.
|
|
14
|
+
However, drawlib want to let user handle image **very very** easy.
|
|
15
|
+
This module and its class ``Pimage`` achieves it.
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
from typing import Union, Tuple, Dict, cast
|
|
23
|
+
from PIL import (
|
|
24
|
+
Image,
|
|
25
|
+
ImageFilter,
|
|
26
|
+
ImageOps,
|
|
27
|
+
ImageEnhance,
|
|
28
|
+
ImageChops,
|
|
29
|
+
)
|
|
30
|
+
from drawlib.v0_1.private.util import (
|
|
31
|
+
error_handler,
|
|
32
|
+
get_script_relative_path,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Dimage:
|
|
37
|
+
"""drawlib image class
|
|
38
|
+
|
|
39
|
+
Providing very easy methods for read/write and applying effects to image.
|
|
40
|
+
This class is wrapper of ``PIL.Image.Image``.
|
|
41
|
+
So, you can get/set PIL image from this class.
|
|
42
|
+
If you needs apply advanced effects, use PIL Image instead.
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
_cache: Dict[str, Dimage] = {}
|
|
47
|
+
|
|
48
|
+
@error_handler
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
image: Union[str, Image.Image, Dimage],
|
|
52
|
+
copy: bool = False,
|
|
53
|
+
):
|
|
54
|
+
"""Initialize Pimage from file, PIL Image, Pimage.
|
|
55
|
+
|
|
56
|
+
Initialize Pimage from file path, PIL Image, Pimage.
|
|
57
|
+
|
|
58
|
+
Note:
|
|
59
|
+
File path is relative to user code which calls ``Pimage()``.
|
|
60
|
+
Not from where you call python (default path behavior).
|
|
61
|
+
If you want to have normal path behavior,
|
|
62
|
+
convert relative path to absolute path.
|
|
63
|
+
And then, pass to this class.
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
# create new PIL.Image instance
|
|
68
|
+
if isinstance(image, str):
|
|
69
|
+
image_str = cast(str, image) # for mypy check
|
|
70
|
+
image_str = get_script_relative_path(image_str)
|
|
71
|
+
if not os.path.exists(image_str):
|
|
72
|
+
raise FileNotFoundError(f'file "{image_str}" does not exist.')
|
|
73
|
+
self._pilimg = Image.open(image_str)
|
|
74
|
+
|
|
75
|
+
elif isinstance(image, Image.Image):
|
|
76
|
+
if copy:
|
|
77
|
+
self._pilimg = image.copy()
|
|
78
|
+
else:
|
|
79
|
+
self._pilimg = image
|
|
80
|
+
|
|
81
|
+
elif isinstance(image, Dimage):
|
|
82
|
+
if copy:
|
|
83
|
+
self._pilimg = image._pilimg.copy()
|
|
84
|
+
else:
|
|
85
|
+
self._pilimg = image._pilimg
|
|
86
|
+
|
|
87
|
+
else:
|
|
88
|
+
raise ValueError(f'Pimage does not support type "{type(image)}".')
|
|
89
|
+
|
|
90
|
+
@error_handler
|
|
91
|
+
def get_pil_image(self) -> Image.Image:
|
|
92
|
+
"""Get **copied** PIL Image.
|
|
93
|
+
|
|
94
|
+
Get **copied** PIL Image which Pimage instance holds.
|
|
95
|
+
Modification to the PIL Image has no effects to Pimage.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
PIL.Image.Image: copy of PIL Image.
|
|
99
|
+
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
return self._pilimg.copy()
|
|
103
|
+
|
|
104
|
+
@error_handler
|
|
105
|
+
def get_image_size(self) -> Tuple[int, int]:
|
|
106
|
+
width, height = self._pilimg.size
|
|
107
|
+
return (width, height)
|
|
108
|
+
|
|
109
|
+
@error_handler
|
|
110
|
+
def copy(self) -> Dimage:
|
|
111
|
+
"""Get copied Pimage
|
|
112
|
+
|
|
113
|
+
Create another Pimage instance which has same content.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Pimage: deep copied image
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
return Dimage(self)
|
|
121
|
+
|
|
122
|
+
@error_handler
|
|
123
|
+
def save(self, file: str) -> None:
|
|
124
|
+
"""Save Pimage data to file
|
|
125
|
+
|
|
126
|
+
Save to specified file path.
|
|
127
|
+
Path is relative to script file which calls this method.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
file: write file path. relative to user script file.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
None
|
|
134
|
+
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
if not isinstance(file, str):
|
|
138
|
+
raise ValueError('arg "file" must be str.')
|
|
139
|
+
|
|
140
|
+
abspath = get_script_relative_path(file)
|
|
141
|
+
directory = os.path.dirname(abspath)
|
|
142
|
+
os.makedirs(directory, exist_ok=True)
|
|
143
|
+
self._pilimg.save(abspath, quality=95)
|
|
144
|
+
|
|
145
|
+
@error_handler
|
|
146
|
+
def border(
|
|
147
|
+
self,
|
|
148
|
+
width: int,
|
|
149
|
+
color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
150
|
+
) -> Dimage:
|
|
151
|
+
print(color)
|
|
152
|
+
|
|
153
|
+
new_img = ImageOps.expand(
|
|
154
|
+
self._pilimg,
|
|
155
|
+
border=width,
|
|
156
|
+
# pillow supports (R, G, B) and (R, G, B, A)
|
|
157
|
+
fill=(color[0], color[1], color[2]),
|
|
158
|
+
)
|
|
159
|
+
return Dimage(new_img)
|
|
160
|
+
|
|
161
|
+
@error_handler
|
|
162
|
+
def rotate(self, angle: float) -> Dimage:
|
|
163
|
+
"""Get rotated new Pimage. Original Pimage is keeped.
|
|
164
|
+
|
|
165
|
+
Get new Pimage which has rotated.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
angle: between 0.0 ~ 360. pixel size can be changed. New area becomes transparent.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Pimage: new rotated image.
|
|
172
|
+
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
newimg = self._pilimg.rotate(
|
|
176
|
+
angle,
|
|
177
|
+
resample=Image.Resampling.BICUBIC,
|
|
178
|
+
expand=True,
|
|
179
|
+
)
|
|
180
|
+
return Dimage(newimg)
|
|
181
|
+
|
|
182
|
+
@error_handler
|
|
183
|
+
def resize(self, width: int, height: int) -> Dimage:
|
|
184
|
+
"""Get resized new Pimage. Original Pimage is keeped.
|
|
185
|
+
|
|
186
|
+
Get new Pimage which has resized.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
width: new image width
|
|
190
|
+
height: new image height
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Pimage: new rotated image.
|
|
194
|
+
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
newimg = self._pilimg.resize(
|
|
198
|
+
(width, height),
|
|
199
|
+
resample=Image.LANCZOS, # pylint: disable=no-member
|
|
200
|
+
)
|
|
201
|
+
return Dimage(newimg)
|
|
202
|
+
|
|
203
|
+
@error_handler
|
|
204
|
+
def flip(self) -> Dimage:
|
|
205
|
+
"""Get flipped new Pimage. Original Pimage is keeped.
|
|
206
|
+
|
|
207
|
+
Get new Pimage which has flip effect.
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
Pimage: new flipped image.
|
|
211
|
+
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
newimg = ImageOps.flip(self._pilimg)
|
|
215
|
+
return Dimage(newimg)
|
|
216
|
+
|
|
217
|
+
@error_handler
|
|
218
|
+
def mirror(self) -> Dimage:
|
|
219
|
+
"""Get mirrored new Pimage. Original Pimage is keeped.
|
|
220
|
+
|
|
221
|
+
Get new Pimage which has mirror effect.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Pimage: new mirror image.
|
|
225
|
+
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
newimg = ImageOps.mirror(self._pilimg)
|
|
229
|
+
return Dimage(newimg)
|
|
230
|
+
|
|
231
|
+
@error_handler
|
|
232
|
+
def invert(self) -> Dimage:
|
|
233
|
+
"""Get inverted new Pimage. Original Pimage is keeped.
|
|
234
|
+
|
|
235
|
+
Get new Pimage which has invert effect.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Pimage: new inverted image.
|
|
239
|
+
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
if "A" not in self._pilimg.mode:
|
|
243
|
+
# has no tranceparency. use function
|
|
244
|
+
newimg = ImageOps.invert(self._pilimg)
|
|
245
|
+
return Dimage(newimg)
|
|
246
|
+
|
|
247
|
+
# Invert RGB channels
|
|
248
|
+
r, g, b, a = self._pilimg.split()
|
|
249
|
+
r = Image.eval(r, lambda x: 255 - x)
|
|
250
|
+
g = Image.eval(g, lambda x: 255 - x)
|
|
251
|
+
b = Image.eval(b, lambda x: 255 - x)
|
|
252
|
+
|
|
253
|
+
# Merge inverted RGB channels with original alpha channel
|
|
254
|
+
inverted_image = Image.merge("RGBA", (r, g, b, a))
|
|
255
|
+
return Dimage(inverted_image)
|
|
256
|
+
|
|
257
|
+
@error_handler
|
|
258
|
+
def grayscale(self) -> Dimage:
|
|
259
|
+
"""Get grayscaled new Pimage. Original Pimage is keeped.
|
|
260
|
+
|
|
261
|
+
Get new Pimage which has grayscale effect.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
Pimage: new grayscaled image.
|
|
265
|
+
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
newimg = self._pilimg.convert("LA")
|
|
269
|
+
return Dimage(newimg)
|
|
270
|
+
|
|
271
|
+
@error_handler
|
|
272
|
+
def brightness(self, brightness_: float = 0.5) -> Dimage:
|
|
273
|
+
"""Get brightness changed new Pimage. Original Pimage is keeped.
|
|
274
|
+
|
|
275
|
+
Get new Pimage which has change brightness effect.
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
Pimage: new brightness changed image.
|
|
279
|
+
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
enhancer = ImageEnhance.Brightness(self._pilimg)
|
|
283
|
+
newimg = enhancer.enhance(brightness_)
|
|
284
|
+
return Dimage(newimg)
|
|
285
|
+
|
|
286
|
+
@error_handler
|
|
287
|
+
def sepia(self) -> Dimage:
|
|
288
|
+
"""Get sepia color new Pimage. Original Pimage is keeped.
|
|
289
|
+
|
|
290
|
+
Get new Pimage which has sepia effect.
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
Pimage: new sepia color image.
|
|
294
|
+
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
gray = self._pilimg.convert("L")
|
|
298
|
+
sepia_image = Image.merge(
|
|
299
|
+
"RGB",
|
|
300
|
+
(
|
|
301
|
+
gray.point(lambda x: x * 240 / 255),
|
|
302
|
+
gray.point(lambda x: x * 200 / 255),
|
|
303
|
+
gray.point(lambda x: x * 145 / 255),
|
|
304
|
+
),
|
|
305
|
+
)
|
|
306
|
+
if "A" not in self._pilimg.mode:
|
|
307
|
+
return Dimage(sepia_image)
|
|
308
|
+
|
|
309
|
+
# add alpha from original
|
|
310
|
+
alpha_mask = self._pilimg.split()[3]
|
|
311
|
+
sepia_image.putalpha(alpha_mask)
|
|
312
|
+
return Dimage(sepia_image)
|
|
313
|
+
|
|
314
|
+
@error_handler
|
|
315
|
+
def colorize(
|
|
316
|
+
self,
|
|
317
|
+
black: Union[str, int],
|
|
318
|
+
white: Union[str, int],
|
|
319
|
+
# black: Union[str, Tuple[int, int, int]],
|
|
320
|
+
# white: Union[str, Tuple[int, int, int]],
|
|
321
|
+
) -> Dimage:
|
|
322
|
+
"""Get colorized new Pimage. Original Pimage is keeped.
|
|
323
|
+
|
|
324
|
+
Get new Pimage which has colorize effect.
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Pimage: new colorized image.
|
|
328
|
+
|
|
329
|
+
"""
|
|
330
|
+
|
|
331
|
+
gray = self._pilimg.convert("L")
|
|
332
|
+
colorized_image = ImageOps.colorize(gray, black=black, white=white)
|
|
333
|
+
if "A" not in self._pilimg.mode:
|
|
334
|
+
return Dimage(colorized_image)
|
|
335
|
+
|
|
336
|
+
# add alpha from original
|
|
337
|
+
alpha_mask = self._pilimg.split()[3]
|
|
338
|
+
colorized_image.putalpha(alpha_mask)
|
|
339
|
+
return Dimage(colorized_image)
|
|
340
|
+
|
|
341
|
+
@error_handler
|
|
342
|
+
def posterize(self, num_colors: int = 4) -> Dimage:
|
|
343
|
+
"""Get posterized new Pimage. Original Pimage is keeped.
|
|
344
|
+
|
|
345
|
+
Get new Pimage which has posterized effect.
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
Pimage: new posterized image.
|
|
349
|
+
|
|
350
|
+
"""
|
|
351
|
+
|
|
352
|
+
if "A" not in self._pilimg.mode:
|
|
353
|
+
newimg = ImageOps.posterize(self._pilimg, num_colors)
|
|
354
|
+
return Dimage(newimg)
|
|
355
|
+
|
|
356
|
+
r, g, b, a = self._pilimg.split()
|
|
357
|
+
r = ImageOps.posterize(r, num_colors)
|
|
358
|
+
g = ImageOps.posterize(g, num_colors)
|
|
359
|
+
b = ImageOps.posterize(b, num_colors)
|
|
360
|
+
newimg = Image.merge("RGBA", (r, g, b, a))
|
|
361
|
+
return Dimage(newimg)
|
|
362
|
+
|
|
363
|
+
@error_handler
|
|
364
|
+
def mosaic(self) -> Dimage:
|
|
365
|
+
"""Get mosiac new Pimage. Original Pimage is keeped.
|
|
366
|
+
|
|
367
|
+
Get new Pimage which has mosaic effect.
|
|
368
|
+
|
|
369
|
+
Returns:
|
|
370
|
+
Pimage: new mosaic image.
|
|
371
|
+
|
|
372
|
+
"""
|
|
373
|
+
|
|
374
|
+
gimg = self._pilimg.filter(ImageFilter.GaussianBlur(4))
|
|
375
|
+
newimg = gimg.resize(
|
|
376
|
+
(self._pilimg.size[0] // 8, self._pilimg.size[1] // 8),
|
|
377
|
+
# [x // 8 for x in self._pilimg.size],
|
|
378
|
+
).resize(self._pilimg.size)
|
|
379
|
+
return Dimage(newimg)
|
|
380
|
+
|
|
381
|
+
@error_handler
|
|
382
|
+
def blur(self) -> Dimage:
|
|
383
|
+
"""Get blur new Pimage. Original Pimage is keeped.
|
|
384
|
+
|
|
385
|
+
Get new Pimage which has blur effect.
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
Pimage: new blur image.
|
|
389
|
+
|
|
390
|
+
"""
|
|
391
|
+
|
|
392
|
+
newimg = self._pilimg.filter(ImageFilter.BLUR)
|
|
393
|
+
return Dimage(newimg)
|
|
394
|
+
|
|
395
|
+
@error_handler
|
|
396
|
+
def line_extraction(self) -> Dimage:
|
|
397
|
+
"""Get line extracted new Pimage. Original Pimage is keeped.
|
|
398
|
+
|
|
399
|
+
Get new Pimage which has line extraction effect.
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
Pimage: new line extracted image.
|
|
403
|
+
|
|
404
|
+
"""
|
|
405
|
+
|
|
406
|
+
gray = self._pilimg.convert("L")
|
|
407
|
+
gray2 = gray.filter(ImageFilter.MaxFilter(5))
|
|
408
|
+
senga_inv = ImageChops.difference(gray, gray2)
|
|
409
|
+
newimg = ImageOps.invert(senga_inv)
|
|
410
|
+
return Dimage(newimg)
|
|
411
|
+
|
|
412
|
+
@error_handler
|
|
413
|
+
def remove_margin(
|
|
414
|
+
self,
|
|
415
|
+
margin_color: Union[None, str, Tuple[int, int, int]],
|
|
416
|
+
) -> Dimage:
|
|
417
|
+
"""Get margin removed new Pimage. Original Pimage is keeped.
|
|
418
|
+
|
|
419
|
+
Get new Pimage which has margin removed.
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
Pimage: new margin removed image.
|
|
423
|
+
|
|
424
|
+
"""
|
|
425
|
+
|
|
426
|
+
if margin_color is None:
|
|
427
|
+
if "A" not in self._pilimg.mode:
|
|
428
|
+
message = "Can't remove transparent margin from RGB image."
|
|
429
|
+
raise ValueError(message)
|
|
430
|
+
crop = self._pilimg.split()[-1].getbbox()
|
|
431
|
+
new_image = self._pilimg.crop(crop)
|
|
432
|
+
return Dimage(new_image)
|
|
433
|
+
|
|
434
|
+
raise NotImplementedError("Implement later")
|
|
435
|
+
|
|
436
|
+
#############
|
|
437
|
+
### Cache ###
|
|
438
|
+
#############
|
|
439
|
+
|
|
440
|
+
@classmethod
|
|
441
|
+
def cache_exist(cls, name: str) -> bool:
|
|
442
|
+
"""check whether having Pimage cache or not.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
name: cache name
|
|
446
|
+
|
|
447
|
+
Returns:
|
|
448
|
+
bool: whether cache exist or not.
|
|
449
|
+
|
|
450
|
+
"""
|
|
451
|
+
|
|
452
|
+
return name in cls._cache
|
|
453
|
+
|
|
454
|
+
@classmethod
|
|
455
|
+
def cache_set(cls, name: str, image: Dimage) -> None:
|
|
456
|
+
"""Set **copied** Pimage cache with provided name key.
|
|
457
|
+
|
|
458
|
+
This method copies original object and set copied one.
|
|
459
|
+
It means you can modify original object after caching.
|
|
460
|
+
It doesn't modify cached object.
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
name: cache key.
|
|
464
|
+
style: Pimage object which you want to cache.
|
|
465
|
+
|
|
466
|
+
Returns:
|
|
467
|
+
None
|
|
468
|
+
|
|
469
|
+
"""
|
|
470
|
+
|
|
471
|
+
cls._cache[name] = image.copy()
|
|
472
|
+
|
|
473
|
+
@classmethod
|
|
474
|
+
def cache_get(cls, name: str) -> Dimage:
|
|
475
|
+
"""Get **copied** Pimage cache via name(key).
|
|
476
|
+
|
|
477
|
+
This method doesn't return original object.
|
|
478
|
+
But **copied** object.
|
|
479
|
+
So, you can modify returned Pimage object.
|
|
480
|
+
It doesn't harm original cached Pimage object.
|
|
481
|
+
|
|
482
|
+
Args:
|
|
483
|
+
name: cache key.
|
|
484
|
+
|
|
485
|
+
Returns:
|
|
486
|
+
Pimage: copy of original cached object.
|
|
487
|
+
|
|
488
|
+
"""
|
|
489
|
+
|
|
490
|
+
if not cls.cache_exist(name):
|
|
491
|
+
raise ValueError(f'Pimage "{name}" is not cached.')
|
|
492
|
+
return cls._cache[name].copy()
|
|
493
|
+
|
|
494
|
+
@classmethod
|
|
495
|
+
def cache_delete(cls, name: str) -> None:
|
|
496
|
+
"""Delete Pimage cache
|
|
497
|
+
|
|
498
|
+
Delete Pimage cache if exist.
|
|
499
|
+
If not exist, just ignore deletion request.
|
|
500
|
+
|
|
501
|
+
Args:
|
|
502
|
+
name: cache key.
|
|
503
|
+
|
|
504
|
+
Returns:
|
|
505
|
+
None
|
|
506
|
+
|
|
507
|
+
"""
|
|
508
|
+
|
|
509
|
+
if cls.cache_exist(name):
|
|
510
|
+
del cls._cache[name]
|