convert-stream 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 convert-stream might be problematic. Click here for more details.

@@ -0,0 +1,493 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ from __future__ import annotations
4
+ from typing import Tuple
5
+ from io import BytesIO
6
+ from PIL import Image, ImageOps, ImageFilter
7
+ from cv2.typing import MatLike
8
+ import cv2
9
+ import numpy as np
10
+
11
+ from soup_files import File
12
+ from convertlib.models.m_imgelib import LibraryImage, ABCImageObject, ABCInvertColor
13
+
14
+ #=============================================================================#
15
+ # Inverter cores em imagens
16
+ #=============================================================================#
17
+ class ImplementInvertColorOpenCv(ABCInvertColor):
18
+ """
19
+ Escurecer texto em imagens.
20
+ """
21
+ def __init__(self, image_bytes):
22
+ super().__init__()
23
+ if not isinstance(image_bytes, bytes):
24
+ raise ValueError(f'{__class__.__name__}\nUse: bytes, não {type(image_bytes)}')
25
+ self.image_bytes:bytes = image_bytes
26
+
27
+ def _image_bytes_to_opencv(self, img_bytes:bytes) -> MatLike:
28
+ """Converte os bytes de uma imagem em objeto opencv MatLike"""
29
+ nparr = np.frombuffer(img_bytes, np.uint8)
30
+ return cv2.imdecode(nparr, cv2.IMREAD_GRAYSCALE)
31
+
32
+ def _image_opencv_tobytes(self, img:MatLike) -> bytes:
33
+ """Convert um objeto opencv MatLike em bytes de imagem"""
34
+ _, buffer = cv2.imencode('.png', img) # Codifica como PNG (ou use '.jpg' para JPEG)
35
+ return buffer.tobytes() # Obtém os bytes da imagem
36
+
37
+ def set_gaussian_blur(self):
38
+ # Aplica um filtro Gaussiano para reduzir o ruído
39
+ _blurred:MatLike = cv2.GaussianBlur(self._image_bytes_to_opencv(self.image_bytes), (3, 3), 0.5)
40
+ self.image_bytes = self._image_opencv_tobytes(_blurred)
41
+
42
+ def __set_black(self):
43
+ # Aplica binarização adaptativa (texto branco, fundo preto)
44
+ binary:MatLike = cv2.adaptiveThreshold(
45
+ self._image_bytes_to_opencv(self.image_bytes),
46
+ 150,
47
+ cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
48
+ cv2.THRESH_BINARY,
49
+ 11,
50
+ 2
51
+ )
52
+ self.image_bytes = self._image_opencv_tobytes(binary)
53
+
54
+ def __set_gray(self):
55
+ # Aplica binarização adaptativa (texto preto, fundo branco)
56
+ _binary = cv2.adaptiveThreshold(
57
+ self._image_bytes_to_opencv(self.image_bytes),
58
+ 150,
59
+ cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
60
+ cv2.THRESH_BINARY_INV, # Inverte o texto para ser branco inicialmente
61
+ 11,
62
+ 2
63
+ )
64
+ self.image_bytes = self._image_opencv_tobytes(_binary)
65
+
66
+ def set_background_black(self):
67
+ self.set_gaussian_blur()
68
+ self.__set_black()
69
+ _result:MatLike = cv2.bitwise_not(self._image_bytes_to_opencv(self.image_bytes))
70
+ self.image_bytes = self._image_opencv_tobytes(_result)
71
+
72
+ def set_background_gray(self):
73
+ self.set_gaussian_blur()
74
+ self.__set_gray()
75
+ _result:MatLike = cv2.bitwise_not(self._image_bytes_to_opencv(self.image_bytes))
76
+ self.image_bytes = self._image_opencv_tobytes(_result)
77
+
78
+ def to_file(self, output_path:File):
79
+ print(f'Salvando: {output_path.basename()}')
80
+ cv2.imwrite(output_path.absolute(), self._image_bytes_to_opencv(self.image_bytes))
81
+
82
+ def to_bytes(self) -> bytes:
83
+ return self.image_bytes
84
+
85
+ def to_pil(self) -> Image.Image:
86
+ """Converte a propriedade bytes em imagem PIL"""
87
+ return Image.open(BytesIO(self.image_bytes))
88
+
89
+ def to_opencv(self) -> cv2.typing.MatLike:
90
+ """Converte a propriedade bytes em imagem objeto opencv"""
91
+ return self._image_bytes_to_opencv(self.image_bytes)
92
+
93
+
94
+ class ImplementInvertColorPIL(ABCInvertColor):
95
+ """
96
+ Implementação da inversão de cores usando PIL (Pillow).
97
+ """
98
+ def __init__(self, image_bytes:bytes):
99
+ super().__init__()
100
+ if not isinstance(image_bytes, bytes):
101
+ raise ValueError(f'{__class__.__name__}\nUse: bytes, não {type(image_bytes)}')
102
+ self.image_bytes:bytes = image_bytes
103
+
104
+ def set_gaussian_blur(self):
105
+ img_pil = Image.open(BytesIO(self.image_bytes))
106
+ # Aplicar um desfoque semelhante ao cv2.GaussianBlur
107
+ blurred:Image.Image = img_pil.filter(ImageFilter.GaussianBlur(radius=1))
108
+ buff = BytesIO()
109
+ blurred.save(buff, 'PNG')
110
+ self.image_bytes = buff.getvalue()
111
+ buff.close()
112
+
113
+ def set_background_black(self):
114
+ img_pil = Image.open(BytesIO(self.image_bytes))
115
+ _result = ImageOps.invert(img_pil.convert("L")) # Converte para escala de cinza
116
+ buff = BytesIO()
117
+ _result.save(buff, 'PNG')
118
+ self.image_bytes = buff.getvalue()
119
+ buff.close()
120
+
121
+ def set_background_gray(self):
122
+ # Abrir a imagem a partir dos bytes
123
+ img_pil = Image.open(BytesIO(self.image_bytes))
124
+
125
+ # Converter para escala de cinza
126
+ gray_img = img_pil.convert("L")
127
+
128
+ # Inverter as cores
129
+ inverted_img = ImageOps.invert(gray_img)
130
+
131
+ # Aplicar um threshold invertido: força fundo branco e texto preto
132
+ threshold = 128 # Ajuste conforme necessário
133
+ binary_img = inverted_img.point(lambda x: 0 if x > threshold else 150) # Invertido aqui!
134
+
135
+ # Salvar de volta para bytes
136
+ buff = BytesIO()
137
+ binary_img.save(buff, 'PNG')
138
+ self.image_bytes = buff.getvalue()
139
+ buff.close()
140
+
141
+ def to_file(self, output_path: File):
142
+ img:Image.Image = Image.open(self.image_bytes)
143
+ img.save(output_path.absolute(), 'PNG')
144
+
145
+ def to_bytes(self) -> bytes:
146
+ buff_img = BytesIO()
147
+ Image.open(BytesIO(self.image_bytes)).save(buff_img, 'PNG')
148
+ bytes_img = buff_img.getvalue()
149
+ buff_img.close()
150
+ return bytes_img
151
+
152
+ def to_pil(self) -> Image:
153
+ return Image.open(BytesIO(self.image_bytes))
154
+
155
+
156
+ class ImageInverColor(ABCInvertColor):
157
+ """
158
+ Escurecer texto em imagens.
159
+ """
160
+ def __init__(self, invert_color:ABCInvertColor):
161
+ if not isinstance(invert_color, ABCInvertColor):
162
+ raise ValueError(f'{__class__.__name__}\nUse: ABCInvertColor(), não {type(invert_color)}')
163
+ self.invert_color:ABCInvertColor = invert_color
164
+
165
+ def set_gaussian_blur(self):
166
+ self.invert_color.set_gaussian_blur()
167
+
168
+ def set_background_black(self):
169
+ self.invert_color.set_background_black()
170
+
171
+ def set_background_gray(self):
172
+ self.invert_color.set_background_gray()
173
+
174
+ def to_file(self, output_path:File):
175
+ return self.invert_color.to_file(output_path)
176
+
177
+ def to_bytes(self):
178
+ return self.invert_color.to_bytes()
179
+
180
+ @classmethod
181
+ def create_from_file(cls, f:File, *, library:LibraryImage=LibraryImage.OPENCV) -> 'ImageInverColor':
182
+ img:ImageObject = ImageObject.create_from_file(f, library=library)
183
+ if library == LibraryImage.OPENCV:
184
+ inv:ABCInvertColor = ImplementInvertColorOpenCv(f.path.read_bytes())
185
+ elif library == LibraryImage.PIL:
186
+ inv:ABCInvertColor = ImplementInvertColorPIL(f.path.read_bytes())
187
+ else:
188
+ raise NotImplementedError(
189
+ f'{__class__.__name__}\nUse: LibraryImage.OPENCV, ou LibraryImage.PIL, não {type(library)}'
190
+ )
191
+ return cls(inv)
192
+
193
+ @classmethod
194
+ def create_from_bytes(cls, bt:bytes, *, library:LibraryImage=LibraryImage.OPENCV) -> 'ImageInverColor':
195
+ if library == LibraryImage.OPENCV:
196
+ invert_color:ABCInvertColor = ImplementInvertColorOpenCv(bt)
197
+ elif library == LibraryImage.PIL:
198
+ invert_color:ABCInvertColor = ImplementInvertColorPIL(bt)
199
+ else:
200
+ raise NotImplementedError(
201
+ f'{__class__.__name__}\nUse: LibraryImage.OPENCV, ou LibraryImage.PIL, não {type(library)}'
202
+ )
203
+ return cls(invert_color)
204
+
205
+ #=============================================================================#
206
+ # Manipulação de imagens
207
+ #=============================================================================#
208
+ class ImageObjectPIL(ABCImageObject):
209
+ """
210
+ Implementação de ImageObject usando PIL.
211
+ """
212
+ def __init__(self, image_bytes:bytes):
213
+ super().__init__()
214
+ if not isinstance(image_bytes, bytes):
215
+ raise ValueError(f'{__class__.__name__} Use: bytes, não {type(image_bytes)}')
216
+ self.current_library = LibraryImage.PIL
217
+ self.image_bytes = image_bytes
218
+ self.max_size:Tuple[int, int] = (1980, 720) # Dimensões máximas, altere se necessário.
219
+
220
+ try:
221
+ img = Image.open(BytesIO(image_bytes))
222
+ except Exception as e:
223
+ raise ValueError(f"{__class__.__name__}\nPIL: Bytes de imagem inválidos")
224
+ else:
225
+ self.dimensions = img.size
226
+
227
+ # Redimensionar, se as dimensões forem maior que self.max_size.
228
+ if img.width > self.max_size[0] or img.height > self.max_size[1]:
229
+ #img.thumbnail(self.max_size, Image.LANCZOS) # Mantém proporção
230
+ buff_image:BytesIO = BytesIO()
231
+ img.save(buff_image, format='PNG', optimize=True, quality=80)
232
+ self.image_bytes = buff_image.getvalue()
233
+ self.dimensions = img.size
234
+ buff_image.seek(0)
235
+ buff_image.close()
236
+ del img
237
+
238
+ def is_paisagem(self) -> bool:
239
+ """
240
+ Retorna True se a imagem estiver em modo paisagem.
241
+ """
242
+ width, height = self.dimensions
243
+ return width > height
244
+
245
+ def set_rotation(self, rotation: LibraryImage = LibraryImage.ROTATION_180):
246
+ img = Image.open(BytesIO(self.image_bytes))
247
+ if rotation == LibraryImage.ROTATION_90:
248
+ img = img.transpose(Image.Transpose.ROTATE_90)
249
+ elif rotation == LibraryImage.ROTATION_180:
250
+ img = img.transpose(Image.Transpose.ROTATE_180)
251
+ elif rotation == LibraryImage.ROTATION_270:
252
+ img = img.transpose(Image.Transpose.ROTATE_270)
253
+ else:
254
+ return
255
+ new_bytes = BytesIO()
256
+ img.save(new_bytes, format='PNG')
257
+ self.image_bytes = new_bytes.getvalue()
258
+
259
+ def set_paisagem(self):
260
+ if not self.is_paisagem():
261
+ img = Image.open(BytesIO(self.image_bytes))
262
+ img = img.transpose(Image.Transpose.ROTATE_90) # Rotaciona -90 graus
263
+ new_bytes = BytesIO()
264
+ img.save(new_bytes, format='PNG')
265
+ self.image_bytes = new_bytes.getvalue()
266
+
267
+ def set_optimize(self):
268
+ optimized_bytes = BytesIO()
269
+ img = self.to_image_pil()
270
+ img.save(optimized_bytes, format='PNG', optimize=True, quality=80)
271
+ self.image_bytes = optimized_bytes.getvalue()
272
+
273
+ def set_background_black(self):
274
+ inv = ImageInverColor.create_from_bytes(self.to_bytes(), library=LibraryImage.PIL)
275
+ inv.set_background_black()
276
+ self.image_bytes = inv.to_bytes()
277
+
278
+ def set_background_gray(self):
279
+ inv = ImageInverColor.create_from_bytes(self.to_bytes(), library=LibraryImage.PIL)
280
+ inv.set_background_gray()
281
+ self.image_bytes = inv.to_bytes()
282
+
283
+ def set_gaussian(self):
284
+ inv = ImageInverColor.create_from_bytes(self.to_bytes(), library=LibraryImage.PIL)
285
+ inv.set_gaussian_blur()
286
+ self.image_bytes = inv.to_bytes()
287
+
288
+ def to_image_pil(self) -> Image.Image:
289
+ return Image.open(BytesIO(self.image_bytes))
290
+
291
+ def to_image_opencv(self) -> cv2.typing.MatLike:
292
+ nparr = np.frombuffer(self.image_bytes, np.uint8)
293
+ return cv2.imdecode(nparr, cv2.IMREAD_COLOR)
294
+
295
+ def to_bytes(self) -> bytes:
296
+ img = self.to_image_pil()
297
+ image_bytes = BytesIO()
298
+ img.save(image_bytes, format='PNG')
299
+ return image_bytes.getvalue()
300
+
301
+ def to_file(self, filepath: str):
302
+ try:
303
+ self.to_image_pil().save(filepath)
304
+ except ImportError:
305
+ raise ImportError("A biblioteca PIL não está instalada. Instale-a com 'pip install Pillow'.")
306
+ except Exception as e:
307
+ raise Exception(f"Erro ao salvar imagem PIL: {e}")
308
+
309
+ class ImageObjectOpenCV(ABCImageObject):
310
+ """
311
+ Implementação de ImageObject usando OpenCV.
312
+ """
313
+ def __init__(self, image_bytes):
314
+ super().__init__()
315
+ if not isinstance(image_bytes, bytes):
316
+ raise ValueError(f'{__class__.__name__} Use: bytes, não {type(image_bytes)}')
317
+ self.current_library = LibraryImage.OPENCV
318
+ self.image_bytes = image_bytes
319
+ self.max_size:Tuple[int, int] = (1980, 720)
320
+
321
+ try:
322
+ nparr = np.frombuffer(self.image_bytes, np.uint8)
323
+ image_opencv:MatLike = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
324
+ except Exception as e:
325
+ print('-' * 80)
326
+ raise ValueError(f"\nCV2: Bytes de imagem OpenCV inválidos")
327
+ else:
328
+ self.dimensions = (image_opencv.shape[1], image_opencv.shape[0]) # (largura, altura)
329
+
330
+ # Redimensionar se necessário
331
+ if self.dimensions[0] > self.max_size[0] or self.dimensions[1] > self.max_size[1]:
332
+ h, w = image_opencv.shape[:2]
333
+ scale = min(self.max_size[0] / w, self.max_size[1] / h)
334
+ new_size = (int(w * scale), int(h * scale))
335
+ image_opencv = cv2.resize(image_opencv, new_size, interpolation=cv2.INTER_LANCZOS4)
336
+ # Converter a imagem de volta para bytes
337
+ _, encoded_img = cv2.imencode('.png', image_opencv)
338
+ self.image_bytes = encoded_img.tobytes()
339
+ # Atualizar dimensões após redimensionamento
340
+ self.dimensions = (image_opencv.shape[1], image_opencv.shape[0])
341
+
342
+ def is_paisagem(self) -> bool:
343
+ """
344
+ Retorna True se a imagem estiver em modo paisagem.
345
+ """
346
+ width, height = self.dimensions
347
+ return width > height
348
+
349
+ def set_rotation(self, rotation: LibraryImage = LibraryImage.ROTATION_180):
350
+ nparr = np.frombuffer(self.image_bytes, np.uint8)
351
+ img:MatLike = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
352
+ if rotation == LibraryImage.ROTATION_90:
353
+ img:MatLike = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
354
+ elif rotation == LibraryImage.ROTATION_180:
355
+ img:MatLike = cv2.rotate(img, cv2.ROTATE_180)
356
+ elif rotation == LibraryImage.ROTATION_270:
357
+ img:MatLike = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
358
+ img:MatLike = cv2.rotate(img, cv2.ROTATE_180)
359
+ else:
360
+ return
361
+ success, encoded_image = cv2.imencode('.png', img)
362
+ if success:
363
+ self.image_bytes = encoded_image.tobytes()
364
+
365
+ def set_paisagem(self):
366
+ if not self.is_paisagem():
367
+ nparr = np.frombuffer(self.image_bytes, np.uint8)
368
+ img:MatLike = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
369
+ img:MatLike = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) # Rotaciona -90 graus
370
+
371
+ success, encoded_image = cv2.imencode('.png', img)
372
+ if success:
373
+ self.image_bytes = encoded_image.tobytes()
374
+
375
+ def set_optimize(self):
376
+ """
377
+ Reduz o tamanho da imagem, e salva a imagen reduzida na propriedade bytes.
378
+ """
379
+ imagem:MatLike = self.to_image_opencv()
380
+ _status, buffer = cv2.imencode(".png", imagem, [cv2.IMWRITE_JPEG_QUALITY, 80])
381
+ if _status:
382
+ self.image_bytes = buffer.tobytes()
383
+
384
+ def set_background_black(self):
385
+ inv = ImageInverColor.create_from_bytes(self.to_bytes(), library=LibraryImage.OPENCV)
386
+ inv.set_background_black()
387
+ self.image_bytes = inv.to_bytes()
388
+
389
+ def set_background_gray(self):
390
+ inv = ImageInverColor.create_from_bytes(self.to_bytes(), library=LibraryImage.OPENCV)
391
+ inv.set_background_gray()
392
+ self.image_bytes = inv.to_bytes()
393
+
394
+ def set_gaussian(self):
395
+ inv = ImageInverColor.create_from_bytes(self.to_bytes(), library=LibraryImage.OPENCV)
396
+ inv.set_gaussian_blur()
397
+ self.image_bytes = inv.to_bytes()
398
+
399
+ def to_image_pil(self) -> Image.Image:
400
+ return Image.open(BytesIO(self.image_bytes))
401
+
402
+ def to_image_opencv(self) -> cv2.typing.MatLike:
403
+ nparr = np.frombuffer(self.image_bytes, np.uint8)
404
+ return cv2.imdecode(nparr, cv2.IMREAD_COLOR)
405
+
406
+ def to_bytes(self) -> bytes:
407
+ _, buffer = cv2.imencode('.png', self.to_image_opencv()) # Codifica como PNG (ou use '.jpg' para JPEG)
408
+ return buffer.tobytes()
409
+
410
+ def to_file(self, filepath: str):
411
+ try:
412
+ img = self.to_image_opencv()
413
+ cv2.imwrite(filepath, img)
414
+ except ImportError:
415
+ raise ImportError("A biblioteca OpenCV não está instalada. Instale-a com 'pip install opencv-python'.")
416
+ except Exception as e:
417
+ raise Exception(f"Erro ao salvar imagem OpenCV: {e}")
418
+
419
+ class ImageObject(ABCImageObject):
420
+ """
421
+ Facade para manipular imagens com PIL ou OPENCV
422
+ """
423
+ def __init__(self, img_obj:ABCImageObject):
424
+ super().__init__()
425
+ self.img_obj:ABCImageObject = img_obj
426
+ self.current_library:LibraryImage = self.img_obj.current_library
427
+
428
+ def set_optimize(self):
429
+ """
430
+ Reduz o tamanho da imagem, e salva a imagen reduzida na propriedade bytes.
431
+ """
432
+ self.img_obj.set_optimize()
433
+
434
+ def set_rotation(self, rotation: LibraryImage = LibraryImage.ROTATION_180):
435
+ self.img_obj.set_rotation(rotation)
436
+
437
+ def set_paisagem(self):
438
+ self.img_obj.set_paisagem()
439
+
440
+ def set_background_gray(self):
441
+ self.img_obj.set_background_gray()
442
+
443
+ def set_background_black(self):
444
+ self.img_obj.set_background_black()
445
+
446
+ def set_gaussian(self):
447
+ self.img_obj.set_gaussian()
448
+
449
+ def to_image_pil(self) -> Image.Image:
450
+ return self.img_obj.to_image_pil()
451
+
452
+ def to_image_opencv(self) -> cv2.typing.MatLike:
453
+ return self.img_obj.to_image_opencv()
454
+
455
+ def to_file(self, f:File):
456
+ self.img_obj.to_file(f.absolute())
457
+
458
+ def is_paisagem(self) -> bool:
459
+ return self.img_obj.is_paisagem()
460
+
461
+ def to_bytes(self) -> bytes:
462
+ return self.img_obj.to_bytes()
463
+
464
+ @classmethod
465
+ def create_from_bytes(cls, image_bytes: bytes, *, library:LibraryImage=LibraryImage.OPENCV) -> 'ImageObject':
466
+ if library == LibraryImage.PIL:
467
+ img = ImageObjectPIL(image_bytes)
468
+ elif library == LibraryImage.OPENCV:
469
+ img = ImageObjectOpenCV(image_bytes)
470
+ else:
471
+ raise ValueError("Biblioteca de imagem inválida.")
472
+ return cls(img)
473
+
474
+ @classmethod
475
+ def create_from_file(cls, filepath: File, *, library:LibraryImage=LibraryImage.OPENCV) -> 'ImageObject':
476
+ print(f'Obtendo imagem do arquivo: {filepath.basename()}')
477
+ try:
478
+ if library == LibraryImage.PIL:
479
+ image = ImageObjectPIL(filepath.path.read_bytes())
480
+ elif library == LibraryImage.OPENCV:
481
+ image = ImageObjectOpenCV(filepath.path.read_bytes())
482
+ else:
483
+ raise ValueError("Biblioteca de imagem inválida.")
484
+ except FileNotFoundError:
485
+ print(f'O arquivo não existe: {filepath.absolute()}')
486
+ raise
487
+ except Exception as e:
488
+ print(e, '\n')
489
+ print('=' * 70)
490
+ raise ValueError(f'{__class__.__name__} Arquivo inválido: [{filepath.absolute()}]')
491
+ return cls(image)
492
+
493
+
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from .models.m_pdf_page import LibraryPDF
4
+ from .models.m_imgelib import LibraryImage
5
+ from .models.m_text import LibraryDates
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env python3
2
+ from .m_text import (
3
+ DataString, TableText, ConvertDate, ArrayString, LibraryDates,
4
+ print_line, print_title, save_data
5
+ )
6
+
7
+ from .m_imgelib import LibraryImage, ABCImageObject, ABCInvertColor
8
+ from .m_pdf_page import LibraryPDF, ABCPagePdf
9
+ from .m_pdf_document import ABCDocumentPdf
10
+ from .m_pdf_convert import ABCConvertPdf, ABCImageConvertPdf, ABCDocumentStream
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+
4
+ from __future__ import annotations
5
+ from abc import ABC, abstractmethod
6
+ from enum import Enum
7
+ from typing import List, Tuple
8
+ from PIL import Image
9
+ from cv2.typing import MatLike
10
+ import cv2
11
+ from soup_files import File
12
+
13
+ class LibraryImage(Enum):
14
+ PIL = 1
15
+ OPENCV = 2
16
+ ROTATION_90 = 90
17
+ ROTATION_180 = 180
18
+ ROTATION_270 = 270
19
+
20
+
21
+
22
+ class ABCInvertColor(ABC):
23
+
24
+ @abstractmethod
25
+ def to_file(self, output_path:File):
26
+ pass
27
+
28
+ @abstractmethod
29
+ def to_bytes(self) -> bytes:
30
+ pass
31
+
32
+ @abstractmethod
33
+ def set_background_black(self):
34
+ pass
35
+
36
+ @abstractmethod
37
+ def set_background_gray(self):
38
+ pass
39
+
40
+ @abstractmethod
41
+ def set_gaussian_blur(self):
42
+ pass
43
+
44
+
45
+ class ABCImageObject(ABC):
46
+ """
47
+ Classe abstrata base para objetos de imagem.
48
+ """
49
+ def __init__(self):
50
+ super().__init__()
51
+ self.current_library: LibraryImage = None
52
+
53
+ @classmethod
54
+ def is_paisagem(self) -> bool:
55
+ """
56
+ Retorna True se a imagem estiver em modo paisagem.
57
+ """
58
+ pass
59
+
60
+ @abstractmethod
61
+ def set_optimize(self):
62
+ pass
63
+
64
+ @abstractmethod
65
+ def to_bytes(self) -> bytes:
66
+ pass
67
+
68
+ @abstractmethod
69
+ def set_paisagem(self):
70
+ pass
71
+
72
+ @abstractmethod
73
+ def set_rotation(self, rotation: LibraryImage = LibraryImage.ROTATION_180):
74
+ pass
75
+
76
+ @abstractmethod
77
+ def set_background_gray(self):
78
+ pass
79
+
80
+ @abstractmethod
81
+ def set_background_black(self):
82
+ pass
83
+
84
+ @abstractmethod
85
+ def set_gaussian(self):
86
+ pass
87
+
88
+ @abstractmethod
89
+ def to_image_pil(self) -> Image.Image:
90
+ pass
91
+
92
+ @abstractmethod
93
+ def to_image_opencv(self) -> cv2.typing.MatLike:
94
+ pass
95
+
96
+ @abstractmethod
97
+ def to_file(self, filepath: object):
98
+ """
99
+ Salva a imagem em um arquivo, garantindo modo paisagem.
100
+ """
101
+ pass
102
+
103
+
104
+
105
+
106
+
107
+