convert-stream 2.2.4__tar.gz → 2.2.6__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 (32) hide show
  1. {convert_stream-2.2.4 → convert_stream-2.2.6}/PKG-INFO +1 -1
  2. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/__init__.py +2 -1
  3. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/_version.py +1 -1
  4. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/enum_libs/enums.py +1 -1
  5. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/image/img_object.py +2 -6
  6. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/pdf/__init__.py +3 -2
  7. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/pdf/image_to_pdf.py +10 -11
  8. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/pdf/pdf_document.py +224 -78
  9. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/pdf/pdf_page.py +1 -1
  10. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/pdf/pdf_to_image.py +1 -1
  11. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/sheets/load.py +14 -19
  12. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/stream.py +11 -7
  13. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/table_files.py +8 -101
  14. convert_stream-2.2.6/convert_stream/text/__init__.py +7 -0
  15. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/text/string.py +0 -25
  16. convert_stream-2.2.6/convert_stream/text/terminal.py +61 -0
  17. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream.egg-info/PKG-INFO +1 -1
  18. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream.egg-info/SOURCES.txt +2 -1
  19. {convert_stream-2.2.4 → convert_stream-2.2.6}/pyproject.toml +1 -1
  20. convert_stream-2.2.4/convert_stream/text/__init__.py +0 -6
  21. {convert_stream-2.2.4 → convert_stream-2.2.6}/README.md +0 -0
  22. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/__main__.py +0 -0
  23. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/enum_libs/modules.py +0 -0
  24. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/image/__init__.py +0 -0
  25. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/sheets/__init__.py +0 -0
  26. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/sheets/parse.py +0 -0
  27. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/sheets/save.py +0 -0
  28. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream/text/date.py +0 -0
  29. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream.egg-info/dependency_links.txt +0 -0
  30. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream.egg-info/requires.txt +0 -0
  31. {convert_stream-2.2.4 → convert_stream-2.2.6}/convert_stream.egg-info/top_level.txt +0 -0
  32. {convert_stream-2.2.4 → convert_stream-2.2.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: convert_stream
3
- Version: 2.2.4
3
+ Version: 2.2.6
4
4
  Summary: Manipulação de documentos PDF e Imagens. Converter, Ler, rotacionar exportar etc.
5
5
  Author: Bruno Chaves
6
6
  Requires-Python: >=3.11
@@ -11,8 +11,9 @@ from convert_stream.enum_libs.modules import (
11
11
  DEFAULT_LIB_IMAGE_TO_PDF, ModPdfToImage, ModulePagePdf, ModuleImage,
12
12
  ModImageToPdf, MOD_FITZ, MOD_PYPDF, MOD_CANVAS, MOD_IMG_PIL, MOD_IMG_OPENCV,
13
13
  )
14
+ from .text.terminal import print_title, print_line
14
15
  from .text.string import (
15
- FindText, ArrayString, print_line, print_title, MapText
16
+ FindText, ArrayString, MapText
16
17
  )
17
18
  from .text.date import ConvertStringDate
18
19
  from convert_stream.image.img_object import (
@@ -5,5 +5,5 @@ __version__ = '2.2'
5
5
  __author__ = 'Bruno Chaves'
6
6
  __license__ = 'MIT'
7
7
  __module_name__ = 'convert_stream'
8
- __modify_date__ = '2025-08-23'
8
+ __modify_date__ = '2025-08-24'
9
9
 
@@ -67,4 +67,4 @@ class RotationAngle(Enum):
67
67
 
68
68
  ROTATION_90 = 90
69
69
  ROTATION_180 = 180
70
- ROTATION_270 = 270
70
+ ROTATION_270 = 270
@@ -12,8 +12,8 @@ import numpy as np
12
12
  from scipy.ndimage import uniform_filter
13
13
  from convert_stream.enum_libs.enums import LibImage, RotationAngle
14
14
  from convert_stream.enum_libs.modules import (
15
- MOD_IMG_OPENCV, MOD_IMG_PIL, ModuleImage, DEFAULT_LIB_IMAGE,
16
- cv2, MatLike, Image, ImageOps, ImageFilter
15
+ MOD_IMG_PIL, ModuleImage, DEFAULT_LIB_IMAGE,
16
+ cv2, MatLike, Image, ImageFilter
17
17
  )
18
18
 
19
19
 
@@ -578,7 +578,3 @@ class CollectionImages(object):
578
578
  def set_pbar(self, p: ProgressBarAdapter) -> None:
579
579
  self.pbar = p
580
580
 
581
-
582
-
583
-
584
-
@@ -3,9 +3,10 @@
3
3
  from convert_stream.enum_libs.enums import LibPDF
4
4
  from convert_stream.enum_libs.modules import (
5
5
  DEFAULT_LIB_PDF, DEFAULT_LIB_PDF_TO_IMG, DEFAULT_LIB_IMAGE_TO_PDF,
6
- ModulePagePdf, MOD_FITZ, MOD_PYPDF, ModPdfToImage, ModImageToPdf
6
+ ModulePagePdf, MOD_FITZ, MOD_PYPDF, ModPdfToImage, ModImageToPdf,
7
+ PdfWriter, PdfReader
7
8
  )
8
- from .pdf_page import PageDocumentPdf, fitz, PdfReader, PdfWriter
9
+ from .pdf_page import PageDocumentPdf, fitz
9
10
  from .pdf_document import (
10
11
  DocumentPdf, DEFAULT_LIB_PDF, ModuleDocPdf, CollectionPagePdf
11
12
  )
@@ -9,7 +9,7 @@ from soup_files import File, Directory, ProgressBarAdapter
9
9
  from abc import ABC, abstractmethod
10
10
  from convert_stream.enum_libs.enums import LibImageToPdf
11
11
  from convert_stream.enum_libs.modules import (
12
- ModImageToPdf, MOD_CANVAS, DEFAULT_LIB_IMAGE_TO_PDF, canvas, Canvas, letter, ImageReader
12
+ MOD_CANVAS, DEFAULT_LIB_IMAGE_TO_PDF, canvas, letter, ImageReader
13
13
  )
14
14
  from convert_stream.pdf import DocumentPdf
15
15
  from convert_stream.pdf.pdf_page import fitz
@@ -91,7 +91,7 @@ class ImplementImageToPdfCanvas(ABCConvertImageToPdf):
91
91
  c.drawImage(img_reader, 0, 0, width=first_img_width, height=first_img_height)
92
92
 
93
93
  # Processa as imagens restantes
94
- for num, img_obj in enumerate(self.collection_images[1:], 1):
94
+ for num, img_obj in enumerate(self.collection_images.images[1:], 1):
95
95
 
96
96
  self.pbar.update(
97
97
  ((num + 1) / max_num) * 100,
@@ -174,7 +174,7 @@ class ImplementImageToPdfPil(ABCConvertImageToPdf):
174
174
 
175
175
  # Redimensiona a imagem
176
176
  resized_image = original_pil_image.resize(
177
- (scaled_width, scaled_height), Image.Resampling.LANCZOS
177
+ (scaled_width, scaled_height), Image.Resampling.LANCZOS
178
178
  )
179
179
 
180
180
  # Cria uma nova imagem de fundo branca com o tamanho A4
@@ -237,8 +237,8 @@ class ImplementImageToPdfFitz(ABCConvertImageToPdf):
237
237
 
238
238
  for num, img_obj in enumerate(self.collection_images.images):
239
239
  self.pbar.update(
240
- ((num+1)/max_num) * 100,
241
- f'Convertendo: [{num+1} de {max_num}]'
240
+ ((num + 1) / max_num) * 100,
241
+ f'Convertendo: [{num + 1} de {max_num}]'
242
242
  )
243
243
  if land_scape:
244
244
  img_obj.set_landscape()
@@ -294,11 +294,11 @@ class ConvertImageToPdf(object):
294
294
  """
295
295
 
296
296
  def __init__(
297
- self,
298
- collection_images: CollectionImages = CollectionImages(),
299
- *,
300
- lib_img_to_pdf: LibImageToPdf = DEFAULT_LIB_IMAGE_TO_PDF
301
- ):
297
+ self,
298
+ collection_images: CollectionImages = CollectionImages(),
299
+ *,
300
+ lib_img_to_pdf: LibImageToPdf = DEFAULT_LIB_IMAGE_TO_PDF
301
+ ):
302
302
  if lib_img_to_pdf == LibImageToPdf.IMAGE_TO_PDF_CANVAS:
303
303
  self.convert: ABCConvertImageToPdf = ImplementImageToPdfCanvas(collection_images)
304
304
  elif lib_img_to_pdf == LibImageToPdf.IMAGE_TO_PDF_PIL:
@@ -347,4 +347,3 @@ class ConvertImageToPdf(object):
347
347
 
348
348
  def set_land_scape(self):
349
349
  self.convert.collection_images.set_land_scape()
350
-
@@ -6,13 +6,107 @@
6
6
  from __future__ import annotations
7
7
  from abc import ABC, abstractmethod
8
8
  from io import BytesIO
9
- from soup_files import File, Directory, LibraryDocs, InputFiles, ProgressBarAdapter
10
- from convert_stream.enum_libs.enums import LibPDF
9
+
10
+ import pandas as pd
11
+ from soup_files import File, Directory, LibraryDocs, InputFiles, ProgressBarAdapter, JsonConvert
12
+ from convert_stream.enum_libs.enums import LibPDF, ColumnsTable
11
13
  from convert_stream.enum_libs.modules import (
12
14
  DEFAULT_LIB_PDF, ModuleDocPdf, ModulePagePdf, PdfWriter, PdfReader, PageObject, fitz,
13
15
  )
14
16
  from convert_stream.image.img_object import get_hash_from_bytes
15
17
  from convert_stream.pdf.pdf_page import PageDocumentPdf
18
+ from convert_stream.text import show_error, show_info, show_warning, MapText, FindText
19
+ from convert_stream.sheets.save import save_data
20
+
21
+
22
+ class SearchableTextPdf(object):
23
+ """
24
+ Esta classe serve para armazenar textos filtrados em documentos PDF
25
+ guardando o texto buscado e outros elementos como a página em que o texto foi
26
+ encontrado, linha e o nome do arquivo.
27
+ """
28
+ def __init__(self, silent: bool = False):
29
+ self.silent = silent
30
+ self.elements: dict[str, list[str]] = {
31
+ ColumnsTable.NUM_PAGE.value: [],
32
+ ColumnsTable.NUM_LINHA.value: [],
33
+ ColumnsTable.TEXT.value: [],
34
+ ColumnsTable.FILE.value: [],
35
+ }
36
+
37
+ def __repr__(self):
38
+ return f'SearchableTextPdf: {self.elements}'
39
+
40
+ def is_empty(self) -> bool:
41
+ return len(self.elements[ColumnsTable.TEXT.value]) == 0
42
+
43
+ @property
44
+ def first(self) -> dict[str, str]:
45
+ if self.is_empty():
46
+ return {}
47
+ return {
48
+ ColumnsTable.NUM_PAGE.value: self.elements[ColumnsTable.NUM_PAGE.value][0],
49
+ ColumnsTable.NUM_LINHA.value: self.elements[ColumnsTable.NUM_LINHA.value][0],
50
+ ColumnsTable.TEXT.value: self.elements[ColumnsTable.TEXT.value][0],
51
+ ColumnsTable.FILE.value: self.elements[ColumnsTable.FILE.value][0],
52
+ }
53
+
54
+ @property
55
+ def last(self) -> dict[str, str]:
56
+ if self.is_empty():
57
+ return {}
58
+ return {
59
+ ColumnsTable.NUM_PAGE.value: self.elements[ColumnsTable.NUM_PAGE.value][-1],
60
+ ColumnsTable.NUM_LINHA.value: self.elements[ColumnsTable.NUM_LINHA.value][-1],
61
+ ColumnsTable.TEXT.value: self.elements[ColumnsTable.TEXT.value][-1],
62
+ ColumnsTable.FILE.value: self.elements[ColumnsTable.FILE.value][-1],
63
+ }
64
+
65
+ @property
66
+ def length(self) -> int:
67
+ return len(self.elements[ColumnsTable.TEXT.value])
68
+
69
+ def get_item(self, idx: int) -> dict[str, str]:
70
+ try:
71
+ return {
72
+ ColumnsTable.NUM_PAGE.value: self.elements[ColumnsTable.NUM_PAGE.value][idx],
73
+ ColumnsTable.NUM_LINHA.value: self.elements[ColumnsTable.NUM_LINHA.value][idx],
74
+ ColumnsTable.TEXT.value: self.elements[ColumnsTable.TEXT.value][idx],
75
+ ColumnsTable.FILE.value: self.elements[ColumnsTable.FILE.value][idx],
76
+ }
77
+ except Exception as err:
78
+ if not self.silent:
79
+ print(err)
80
+ return {}
81
+
82
+ def add_line(self, text, *, num_page: str, num_line: str, file: str) -> None:
83
+ if not self.silent:
84
+ print(f'{file} => {text}')
85
+ self.elements[ColumnsTable.NUM_PAGE.value].append(num_page)
86
+ self.elements[ColumnsTable.NUM_LINHA.value].append(num_line)
87
+ self.elements[ColumnsTable.TEXT.value].append(text)
88
+ self.elements[ColumnsTable.FILE.value].append(file)
89
+
90
+ def clear(self) -> None:
91
+ for _k in self.elements.keys():
92
+ self.elements[_k].clear()
93
+
94
+ def to_string(self) -> str:
95
+ try:
96
+ return ' '.join(self.elements[ColumnsTable.TEXT.value])
97
+ except Exception as e:
98
+ print(e)
99
+ return 'nas'
100
+
101
+ def to_data_frame(self) -> pd.DataFrame:
102
+ return pd.DataFrame.from_dict(self.elements)
103
+
104
+ def to_file_json(self, file: File):
105
+ dt = JsonConvert.from_dict(self.elements).to_json_data()
106
+ dt.to_file(file)
107
+
108
+ def to_file_excel(self, file: File):
109
+ save_data(self.to_data_frame(), file=file)
16
110
 
17
111
 
18
112
  class ABCDocument(ABC):
@@ -58,14 +152,6 @@ class ABCDocument(ABC):
58
152
  def to_pages(self) -> list[PageDocumentPdf]:
59
153
  pass
60
154
 
61
- @abstractmethod
62
- def to_list(self, separator: str = '\n') -> list[str]:
63
- pass
64
-
65
- @abstractmethod
66
- def to_dict(self, separator: str = '\n') -> dict[str, list[str]]:
67
- pass
68
-
69
155
  @classmethod
70
156
  def create_from_file(cls, file: File) -> ABCDocument:
71
157
  pass
@@ -79,7 +165,7 @@ class ImplementDocumentFitz(ABCDocument):
79
165
 
80
166
  def __init__(self, mod_doc_pdf: ModuleDocPdf, name: str):
81
167
  super().__init__(mod_doc_pdf, name)
82
- self.mod_doc_pdf: fitz.Document = mod_doc_pdf
168
+ self.mod_doc_pdf: ModuleDocPdf = mod_doc_pdf
83
169
  self.lib_pdf: LibPDF = LibPDF.FITZ
84
170
 
85
171
  def get_first_page(self) -> PageDocumentPdf:
@@ -94,7 +180,7 @@ class ImplementDocumentFitz(ABCDocument):
94
180
  if 0 <= idx < self.mod_doc_pdf.page_count:
95
181
  pg = self.mod_doc_pdf.load_page(idx) # retorna fitz.Page
96
182
  if pg is not None:
97
- _page_pdf = PageDocumentPdf.create_from_page_fitz(pg, idx)
183
+ _page_pdf = PageDocumentPdf.create_from_page_fitz(pg)
98
184
  return _page_pdf
99
185
 
100
186
  def get_number_pages(self) -> int:
@@ -102,7 +188,6 @@ class ImplementDocumentFitz(ABCDocument):
102
188
 
103
189
  def add_page(self, page: PageDocumentPdf):
104
190
  # Assume que page.mod_page é fitz.Page
105
- # temp_doc = fitz.open()
106
191
  self.mod_doc_pdf.insert_pdf(
107
192
  page.implement_page_pdf.mod_page.parent,
108
193
  from_page=page.implement_page_pdf.mod_page.number,
@@ -114,7 +199,10 @@ class ImplementDocumentFitz(ABCDocument):
114
199
  self.add_page(page)
115
200
 
116
201
  def to_file(self, file: File):
117
- self.mod_doc_pdf.save(file.path)
202
+ try:
203
+ self.mod_doc_pdf.save(file.path)
204
+ except Exception as e:
205
+ show_warning(f'{e}')
118
206
 
119
207
  def to_bytes(self) -> BytesIO:
120
208
  buf = BytesIO()
@@ -129,27 +217,10 @@ class ImplementDocumentFitz(ABCDocument):
129
217
  pages.append(page_pdf)
130
218
  return pages
131
219
 
132
- def to_list(self, separator: str = '\n') -> list[str]:
133
- pages: list[PageDocumentPdf] = self.to_pages()
134
- values = []
135
- for pg in pages:
136
- values.extend(pg.to_list(separator))
137
- return values
138
-
139
- def to_dict(self, separator: str = '\n') -> dict[str, list[str]]:
140
- pages_pdf = self.to_pages()
141
- document_dict = PageDocumentPdf.DEFAULT_DICT
142
- for pg in pages_pdf:
143
- page_dict = pg.to_dict(separator)
144
- document_dict['TEXTO'].extend(page_dict['TEXTO'])
145
- document_dict['NUM_PAGE'].extend(page_dict['NUM_PAGE'])
146
- document_dict['NUM_LINHA'].extend(page_dict['NUM_LINHA'])
147
- return document_dict
148
-
149
220
  @classmethod
150
221
  def create_from_bytes(cls, bt: BytesIO) -> ImplementDocumentFitz:
151
222
  # Cria documento a partir de BytesIO
152
- doc = fitz.open(stream=bt.getvalue(), filetype="pdf")
223
+ doc: ModuleDocPdf = fitz.open(stream=bt.getvalue(), filetype="pdf")
153
224
  name = get_hash_from_bytes(bt)
154
225
  return cls(doc, name)
155
226
 
@@ -172,7 +243,6 @@ class ImplementDocumentFitz(ABCDocument):
172
243
  from_page=page.implement_page_pdf.mod_page.number,
173
244
  to_page=page.implement_page_pdf.mod_page.number
174
245
  )
175
-
176
246
  bt = BytesIO(pdf_document.write())
177
247
  return cls.create_from_bytes(bt)
178
248
 
@@ -238,23 +308,6 @@ class ImplementDocumentPyPdf(ABCDocument):
238
308
  pages_pdf.append(pg)
239
309
  return pages_pdf
240
310
 
241
- def to_list(self, separator: str = '\n') -> list[str]:
242
- pages: list[PageDocumentPdf] = self.to_pages()
243
- values = []
244
- for pg in pages:
245
- values.extend(pg.to_list(separator))
246
- return values
247
-
248
- def to_dict(self, separator: str = '\n') -> dict[str, list[str]]:
249
- pages_pdf = self.to_pages()
250
- document_dict = PageDocumentPdf.DEFAULT_DICT
251
- for pg in pages_pdf:
252
- page_dict = pg.to_dict(separator)
253
- document_dict['TEXTO'].extend(page_dict['TEXTO'])
254
- document_dict['NUM_PAGE'].extend(page_dict['NUM_PAGE'])
255
- document_dict['NUM_LINHA'].extend(page_dict['NUM_LINHA'])
256
- return document_dict
257
-
258
311
  @classmethod
259
312
  def create_from_bytes(cls, bt: BytesIO) -> ImplementDocumentPyPdf:
260
313
  # Usa PdfReader diretamente de BytesIO
@@ -265,7 +318,6 @@ class ImplementDocumentPyPdf(ABCDocument):
265
318
  pdf_writer = PdfWriter()
266
319
  for page in reader.pages:
267
320
  pdf_writer.add_page(page)
268
-
269
321
  bt.close()
270
322
  del bt
271
323
  del reader
@@ -342,36 +394,130 @@ class DocumentPdf(object):
342
394
  return self.doc_pdf.to_pages()
343
395
 
344
396
  def to_list(self, separator: str = '\n') -> list[str]:
345
- return self.doc_pdf.to_list(separator)
397
+ _pages = self.to_pages()
398
+ _values = []
399
+ for page in _pages:
400
+ try:
401
+ _values.extend(page.to_string().split(separator))
402
+ except Exception as e:
403
+ show_warning(f'{e}')
404
+ return _values
346
405
 
347
406
  def to_dict(self, separator: str = '\n') -> dict[str, list[str]]:
348
- return self.doc_pdf.to_dict(separator)
349
-
350
- def find(self, text_find: str, *, separator: str = '\n', iqual: bool = False, case: bool = False) -> str | None:
351
- _find_item = None
352
- pages = self.to_pages()
353
- for pg in pages:
354
- page_text_str = pg.find(text_find, separator=separator, iqual=iqual, case=case)
355
- if page_text_str is not None:
356
- _find_item = page_text_str
357
- break
358
- pages.clear()
359
- del pages
360
- return _find_item
361
-
362
- def find_all(self, text: str, *, separator: str = '\n', iqual: bool = False, case: bool = True) -> list[str]:
363
- if text is None:
364
- raise ValueError(f'{__class__.__name__}: o texto de pesquisa {text} é nulo!')
365
- elements = []
407
+ dict_doc = {
408
+ ColumnsTable.NUM_PAGE.value: [],
409
+ ColumnsTable.NUM_LINHA.value: [],
410
+ ColumnsTable.TEXT.value: [],
411
+ ColumnsTable.FILENAME.value: [],
412
+ }
366
413
  pages = self.to_pages()
367
- for pg in pages:
368
- page_text_str = pg.find(text, separator=separator, iqual=iqual, case=case)
369
- if page_text_str is not None:
370
- elements.append(text)
371
- break
372
- pages.clear()
373
- del pages
374
- return elements
414
+ for page in pages:
415
+ try:
416
+ _mp = MapText(page.to_list(separator))
417
+ _mp.add_column(ColumnsTable.NUM_PAGE.value, [f'{page.number_page}'] * _mp.length)
418
+ _mp.add_column(ColumnsTable.NUM_PAGE.value, [self.name] * _mp.length)
419
+ except Exception as e:
420
+ show_warning(f'{e}')
421
+ else:
422
+ dict_doc[ColumnsTable.NUM_PAGE.value].extend(_mp.map_elements[ColumnsTable.NUM_PAGE.value])
423
+ dict_doc[ColumnsTable.NUM_LINHA.value].extend(_mp.map_elements[ColumnsTable.NUM_LINHA.value])
424
+ dict_doc[ColumnsTable.TEXT.value].extend(_mp.map_elements[ColumnsTable.TEXT.value])
425
+ dict_doc[ColumnsTable.FILENAME.value].extend(_mp.map_elements[ColumnsTable.FILENAME.value])
426
+ del _mp
427
+ return dict_doc
428
+
429
+ def find(
430
+ self, text: str,
431
+ separator: str = '\n',
432
+ iqual: bool = False,
433
+ case: bool = False,
434
+ silent: bool = False,
435
+ ) -> SearchableTextPdf:
436
+ """
437
+ Filtrar texto retornando a primeira ocorrência do Documento PDF.
438
+ """
439
+ _searchable = SearchableTextPdf(silent)
440
+ pages_pdf = self.to_pages()
441
+ for page_pdf in pages_pdf:
442
+ text_str_in_page = page_pdf.to_string()
443
+ if (text_str_in_page == 'nas') or (text_str_in_page is None):
444
+ continue
445
+ try:
446
+ fd = FindText(text_str_in_page, separator=separator)
447
+ idx = fd.index(text, iqual=iqual, case=case)
448
+ if idx is None:
449
+ continue
450
+ math_text = fd.get_index(idx)
451
+ except:
452
+ pass
453
+ else:
454
+ _searchable.add_line(
455
+ math_text,
456
+ num_page=str(page_pdf.number_page),
457
+ num_line=str(idx + 1),
458
+ file=self.name,
459
+ )
460
+ return _searchable
461
+ return _searchable
462
+
463
+ def find_all(
464
+ self, text: str,
465
+ separator: str = '\n',
466
+ iqual: bool = False,
467
+ case: bool = False,
468
+ silent: bool = False,
469
+ ) -> SearchableTextPdf:
470
+ """
471
+ Filtrar texto em documento PDF e retorna todas as ocorrências do texto
472
+ encontradas no documento, incluindo o número da linha, página e nome do arquivo
473
+ em cada ocorrência.
474
+ """
475
+ _searchable = SearchableTextPdf(silent)
476
+ _pages_pdf = self.to_pages()
477
+ for page_pdf in _pages_pdf:
478
+ text_str_in_page = page_pdf.to_string()
479
+ if (text_str_in_page == 'nas') or (text_str_in_page is None):
480
+ continue
481
+ try:
482
+ _values = text_str_in_page.split(separator)
483
+ for num, item in enumerate(_values):
484
+ if case:
485
+ if iqual:
486
+ if text == item:
487
+ _searchable.add_line(
488
+ item,
489
+ num_page=str(page_pdf.number_page),
490
+ num_line=str(num + 1),
491
+ file=self.name,
492
+ )
493
+ else:
494
+ if text in item:
495
+ _searchable.add_line(
496
+ item,
497
+ num_page=str(page_pdf.number_page),
498
+ num_line=str(num + 1),
499
+ file=self.name,
500
+ )
501
+ else:
502
+ if iqual:
503
+ if text.lower() == item.lower():
504
+ _searchable.add_line(
505
+ item,
506
+ num_page=str(page_pdf.number_page),
507
+ num_line=str(num + 1),
508
+ file=self.name,
509
+ )
510
+ else:
511
+ if text.lower() in item.lower():
512
+ _searchable.add_line(
513
+ item,
514
+ num_page=str(page_pdf.number_page),
515
+ num_line=str(num + 1),
516
+ file=self.name,
517
+ )
518
+ except Exception as e:
519
+ show_warning(f'{__class__.__name__} {e}')
520
+ return _searchable
375
521
 
376
522
  @classmethod
377
523
  def create_from_bytes(cls, bt: BytesIO, *, lib_pdf: LibPDF = LibPDF.FITZ) -> DocumentPdf:
@@ -7,7 +7,7 @@ from __future__ import annotations
7
7
  from abc import ABC, abstractmethod
8
8
  from convert_stream.enum_libs.enums import LibPDF, ColumnsTable
9
9
  from convert_stream.enum_libs.modules import (
10
- ModulePagePdf, PageObject, PdfWriter, PdfReader, fitz
10
+ ModulePagePdf, PageObject, fitz
11
11
  )
12
12
  from convert_stream.text.string import FindText, ArrayString, MapText
13
13
 
@@ -5,7 +5,7 @@
5
5
  """
6
6
  from __future__ import annotations
7
7
  from abc import ABC, abstractmethod
8
- from soup_files import File, Directory, ProgressBarAdapter, CreatePbar
8
+ from soup_files import Directory, ProgressBarAdapter, CreatePbar
9
9
  from convert_stream.enum_libs.enums import LibPdfToImage
10
10
  from convert_stream.enum_libs.modules import DEFAULT_LIB_PDF_TO_IMG, DEFAULT_LIB_IMAGE
11
11
  from convert_stream.image.img_object import ImageObject, LibImage, CollectionImages
@@ -1,26 +1,23 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
3
  from __future__ import annotations
4
- import sys
5
4
  from abc import ABC, abstractmethod
6
- from typing import Optional, List
7
5
  from openpyxl import Workbook, load_workbook
8
6
  from openpyxl.worksheet._read_only import ReadOnlyWorksheet
9
7
  from pandas.io.parsers import TextFileReader
10
8
  import pandas as pd
11
9
  import csv
12
- from soup_files import File, Directory, ProgressBarAdapter, CreatePbar
13
- from soup_files.files import ExtensionFiles
10
+ from soup_files import File, ProgressBarAdapter, CreatePbar
14
11
 
15
12
 
16
13
  class ABCSheetReader(ABC):
17
14
  """Classe abstrata para leitura de planilhas CSV e EXCEL"""
18
15
 
19
16
  def __init__(
20
- self,
21
- file: File, *,
22
- pbar: ProgressBarAdapter = CreatePbar().get()
23
- ):
17
+ self,
18
+ file: File, *,
19
+ pbar: ProgressBarAdapter = CreatePbar().get()
20
+ ):
24
21
  self.pbar: ProgressBarAdapter = pbar
25
22
  self.file: File = file
26
23
  self.df = None
@@ -117,8 +114,8 @@ class ReaderCsv(ABCSheetReader):
117
114
  total_lines = self.get_total_rows()
118
115
  chunks_text: list[TextFileReader] = []
119
116
  for num, chunk in enumerate(
120
- pd.read_csv(self.file.absolute(), chunksize=1000, sep=self.separator),
121
- ):
117
+ pd.read_csv(self.file.absolute(), chunksize=1000, sep=self.separator),
118
+ ):
122
119
  percent: float = (((num + 1) * 1000) / total_lines) * 100
123
120
  self.pbar.update(percent, f"Lendo CSV [{self.file.basename()}]")
124
121
  chunks_text.append(chunk)
@@ -138,9 +135,9 @@ class ReaderCsv(ABCSheetReader):
138
135
  class ReaderExcel(ABCSheetReader):
139
136
 
140
137
  def __init__(
141
- self, file: File, *,
142
- pbar: ProgressBarAdapter = CreatePbar().get()
143
- ):
138
+ self, file: File, *,
139
+ pbar: ProgressBarAdapter = CreatePbar().get()
140
+ ):
144
141
  super().__init__(file, pbar=pbar)
145
142
  self.df = pd.DataFrame()
146
143
 
@@ -315,10 +312,10 @@ class ReaderOds(ABCSheetReader):
315
312
  class ReadFileSheet(object):
316
313
 
317
314
  def __init__(
318
- self, file: File, *,
319
- separator: str = '\t',
320
- pbar: ProgressBarAdapter = CreatePbar().get()
321
- ):
315
+ self, file: File, *,
316
+ separator: str = '\t',
317
+ pbar: ProgressBarAdapter = CreatePbar().get()
318
+ ):
322
319
  if file.is_csv():
323
320
  self.sheet_reader: ABCSheetReader = ReaderCsv(file, pbar=pbar, separator=separator)
324
321
  elif file.is_excel():
@@ -345,5 +342,3 @@ class ReadFileSheet(object):
345
342
 
346
343
  def get_dataframe(self, sheet_name: str = None, *, progress: bool = True) -> pd.DataFrame:
347
344
  return self.sheet_reader.get_dataframe(sheet_name, progress=progress)
348
-
349
-
@@ -42,8 +42,7 @@ class ImageStream(CollectionImages):
42
42
  class PdfStream(object):
43
43
 
44
44
  def __init__(
45
- self,
46
- collection_pages: CollectionPagePdf = CollectionPagePdf(), *,
45
+ self, *,
47
46
  pbar: ProgressBarAdapter = ProgressBarAdapter(),
48
47
  lib_pdf: LibPDF = DEFAULT_LIB_PDF,
49
48
  lib_img: LibImage = DEFAULT_LIB_IMAGE,
@@ -51,7 +50,7 @@ class PdfStream(object):
51
50
  lib_pdf_to_img: LibPdfToImage = DEFAULT_LIB_PDF_TO_IMG,
52
51
  ) -> None:
53
52
  self.progress: ProgressBarAdapter = pbar
54
- self.collection_pages: CollectionPagePdf = collection_pages
53
+ self.collection_pages: CollectionPagePdf = CollectionPagePdf()
55
54
  self.collection_images: CollectionImages = CollectionImages()
56
55
  self.collection_images.set_pbar(pbar)
57
56
  self.collection_pages.set_pbar(pbar)
@@ -59,9 +58,10 @@ class PdfStream(object):
59
58
  self.lib_img: LibImage = lib_img
60
59
  self.lib_img_to_pdf: LibImageToPdf = lib_img_to_pdf
61
60
  self.lib_pdf_to_img: LibPdfToImage = lib_pdf_to_img
61
+ self.clear()
62
62
 
63
63
  @property
64
- def is_null(self) -> bool:
64
+ def is_empty(self) -> bool:
65
65
  return self.collection_pages.is_null
66
66
 
67
67
  def set_land_scape(self):
@@ -111,13 +111,17 @@ class PdfStream(object):
111
111
  def to_document(self) -> DocumentPdf:
112
112
  if self.collection_pages.is_null and self.collection_images.is_empty:
113
113
  raise ValueError('Adicione imagens e/ou documentos para prosseguir!')
114
-
115
- _doc = DocumentPdf.create_from_pages(self.collection_pages.pages)
114
+ _doc = None
115
+ if not self.collection_pages.is_null:
116
+ _doc = DocumentPdf.create_from_pages(self.collection_pages.pages)
116
117
  if not self.collection_images.is_empty:
117
118
  _convert_img_to_pdf = ConvertImageToPdf(self.collection_images)
118
119
  _pages = _convert_img_to_pdf.to_document().to_pages()
119
120
  self.collection_images.clear()
120
- _doc.add_pages(_pages)
121
+ if _doc is None:
122
+ _doc = DocumentPdf.create_from_pages(_pages)
123
+ else:
124
+ _doc.add_pages(_pages)
121
125
  return _doc
122
126
 
123
127
  def to_files_images(
@@ -2,15 +2,14 @@
2
2
 
3
3
  from __future__ import annotations
4
4
  from abc import ABC, abstractmethod
5
- from enum import Enum
6
-
7
5
  from soup_files import (
8
6
  File, Directory, ProgressBarAdapter, CreatePbar,
9
7
  InputFiles, LibraryDocs, JsonConvert, JsonData
10
8
  )
11
9
  from convert_stream.enum_libs.enums import ColumnsTable
12
- from convert_stream import FindText, ArrayString, save_data, MapText
13
- from convert_stream.stream import PdfStream, DocumentPdf, CollectionPagePdf
10
+ from convert_stream.text.string import FindText, ArrayString, MapText
11
+ from convert_stream.pdf.pdf_document import SearchableTextPdf, DocumentPdf
12
+ from convert_stream.stream import PdfStream, CollectionPagePdf
14
13
  import pandas as pd
15
14
 
16
15
 
@@ -209,97 +208,6 @@ class FileToTable(object):
209
208
  return cls(TableFilesPdf())
210
209
 
211
210
 
212
- class SearchableTextPdf(object):
213
- """
214
- Esta classe serve para armazenar textos filtrados em documentos PDF
215
- guardando o texto buscado e outros elementos como a página em que o texto foi
216
- encontrado, linha e o nome do arquivo.
217
-
218
- """
219
- def __init__(self, silent: bool = False):
220
- self.silent = silent
221
- self.elements: dict[str, list[str]] = {
222
- ColumnsTable.NUM_PAGE.value: [],
223
- ColumnsTable.NUM_LINHA.value: [],
224
- ColumnsTable.TEXT.value: [],
225
- ColumnsTable.FILE.value: [],
226
- }
227
-
228
- def __repr__(self):
229
- return f'SearchableTextPdf: {self.elements}'
230
-
231
- def is_empty(self) -> bool:
232
- return len(self.elements[ColumnsTable.TEXT.value]) == 0
233
-
234
- @property
235
- def first(self) -> dict[str, str]:
236
- if self.is_empty():
237
- return {}
238
- return {
239
- ColumnsTable.NUM_PAGE.value: self.elements[ColumnsTable.NUM_PAGE.value][0],
240
- ColumnsTable.NUM_LINHA.value: self.elements[ColumnsTable.NUM_LINHA.value][0],
241
- ColumnsTable.TEXT.value: self.elements[ColumnsTable.TEXT.value][0],
242
- ColumnsTable.FILE.value: self.elements[ColumnsTable.FILE.value][0],
243
- }
244
-
245
- @property
246
- def last(self) -> dict[str, str]:
247
- if self.is_empty():
248
- return {}
249
- return {
250
- ColumnsTable.NUM_PAGE.value: self.elements[ColumnsTable.NUM_PAGE.value][-1],
251
- ColumnsTable.NUM_LINHA.value: self.elements[ColumnsTable.NUM_LINHA.value][-1],
252
- ColumnsTable.TEXT.value: self.elements[ColumnsTable.TEXT.value][-1],
253
- ColumnsTable.FILE.value: self.elements[ColumnsTable.FILE.value][-1],
254
- }
255
-
256
- @property
257
- def length(self) -> int:
258
- return len(self.elements[ColumnsTable.TEXT.value])
259
-
260
- def get_item(self, idx: int) -> dict[str, str]:
261
- try:
262
- return {
263
- ColumnsTable.NUM_PAGE.value: self.elements[ColumnsTable.NUM_PAGE.value][idx],
264
- ColumnsTable.NUM_LINHA.value: self.elements[ColumnsTable.NUM_LINHA.value][idx],
265
- ColumnsTable.TEXT.value: self.elements[ColumnsTable.TEXT.value][idx],
266
- ColumnsTable.FILE.value: self.elements[ColumnsTable.FILE.value][idx],
267
- }
268
- except Exception as err:
269
- if not self.silent:
270
- print(err)
271
- return {}
272
-
273
- def add_line(self, text, *, num_page: str, num_line: str, file: str) -> None:
274
- if not self.silent:
275
- print(f'{file} => {text}')
276
- self.elements[ColumnsTable.NUM_PAGE.value].append(num_page)
277
- self.elements[ColumnsTable.NUM_LINHA.value].append(num_line)
278
- self.elements[ColumnsTable.TEXT.value].append(text)
279
- self.elements[ColumnsTable.FILE.value].append(file)
280
-
281
- def clear(self) -> None:
282
- for _k in self.elements.keys():
283
- self.elements[_k].clear()
284
-
285
- def to_string(self) -> str:
286
- try:
287
- return ' '.join(self.elements[ColumnsTable.TEXT.value])
288
- except Exception as e:
289
- print(e)
290
- return 'nas'
291
-
292
- def to_data_frame(self) -> pd.DataFrame:
293
- return pd.DataFrame.from_dict(self.elements)
294
-
295
- def to_file_json(self, file: File):
296
- dt = JsonConvert.from_dict(self.elements).to_json_data()
297
- dt.to_file(file)
298
-
299
- def to_file_excel(self, file: File):
300
- save_data(self.to_data_frame(), file=file)
301
-
302
-
303
211
  class PdfFinder(object):
304
212
  """
305
213
  Classe para Filtrar texto em documentos PDF,
@@ -328,15 +236,14 @@ class PdfFinder(object):
328
236
  self.add_files_pdf(files)
329
237
 
330
238
  def find(
331
- self, text: str,
332
- separator: str = '\n',
333
- iqual: bool = False,
334
- case: bool = False,
335
- silent: bool = False,
239
+ self, text: str,
240
+ separator: str = '\n',
241
+ iqual: bool = False,
242
+ case: bool = False,
243
+ silent: bool = False,
336
244
  ) -> SearchableTextPdf:
337
245
  """
338
246
  Filtrar texto retornando a primeira ocorrência do Documento PDF.
339
- :param text: texto a ser filtrado no documento
340
247
  """
341
248
  _searchable = SearchableTextPdf(silent)
342
249
  if self.is_empty():
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env python3
2
+ from .date import ConvertStringDate
3
+ from .string import ArrayString, FindText, MapText
4
+ from .terminal import (
5
+ print_line, print_title, show_error, show_warning, show_info, Colors, msg
6
+ )
7
+
@@ -1,33 +1,8 @@
1
1
  #!/usr/bin/env python3
2
2
  from __future__ import annotations
3
- import os
4
3
  import pandas as pd
5
4
 
6
5
 
7
- def print_line(char: str = '='):
8
- """
9
- Imprime uma linha na tela.
10
- """
11
- try:
12
- num_size = os.get_terminal_size().columns
13
- except:
14
- num_size = 80
15
- print(char * num_size)
16
-
17
-
18
- def print_title(title: str, char: str = '='):
19
- """
20
- Imprime um título na tela.
21
- """
22
- try:
23
- num_size = os.get_terminal_size().columns
24
- except:
25
- num_size = 80
26
-
27
- # print_line(char)
28
- print(title.center(num_size, char))
29
-
30
-
31
6
  class MapText(object):
32
7
 
33
8
  def __init__(
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+ import os
3
+ from enum import Enum
4
+
5
+
6
+ class Colors(Enum):
7
+
8
+ GREEN = '\033[92m'
9
+ YELLOW = '\033[93m'
10
+ RED = '\033[91m'
11
+ DARK_RED = '\033[91m'
12
+ DARK_GREEN = '\033[92m'
13
+ DARK_YELLOW = '\033[93m'
14
+ VOID = '\033[0m'
15
+ END = '\033[0m'
16
+
17
+
18
+ def print_line(char: str = '=', *, color: Colors = Colors.VOID):
19
+ """
20
+ Imprime uma linha na tela.
21
+ """
22
+ try:
23
+ num_size = os.get_terminal_size().columns
24
+ except:
25
+ num_size = 80
26
+ print(f'{color.value}{char}{Colors.END.value}' * num_size)
27
+
28
+
29
+ def print_title(title: str, char: str = '='):
30
+ """
31
+ Imprime um título na tela.
32
+ """
33
+ try:
34
+ num_size = os.get_terminal_size().columns
35
+ except:
36
+ num_size = 80
37
+
38
+ # print_line(char)
39
+ print(title.center(num_size, char))
40
+
41
+
42
+ def msg(text: str, *, color: Colors = Colors.VOID):
43
+ print(f'{color.value}{text}{Colors.END.value}')
44
+
45
+
46
+ def show_warning(text: str, *, line: bool = True):
47
+ if line:
48
+ print_line('-')
49
+ print(f'{Colors.DARK_YELLOW}[?] WARNING:{Colors.END.value} {text}')
50
+
51
+
52
+ def show_error(text: str, *, line: bool = True):
53
+ if line:
54
+ print_line('-')
55
+ print(f'{Colors.DARK_YELLOW}[!] ERRO:{Colors.END.value} {text}')
56
+
57
+
58
+ def show_info(text: str, *, line: bool = True):
59
+ if line:
60
+ print_line('-')
61
+ print(f'{Colors.DARK_YELLOW}[+] INFO:{Colors.END.value} {text}')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: convert_stream
3
- Version: 2.2.4
3
+ Version: 2.2.6
4
4
  Summary: Manipulação de documentos PDF e Imagens. Converter, Ler, rotacionar exportar etc.
5
5
  Author: Bruno Chaves
6
6
  Requires-Python: >=3.11
@@ -25,4 +25,5 @@ convert_stream/sheets/parse.py
25
25
  convert_stream/sheets/save.py
26
26
  convert_stream/text/__init__.py
27
27
  convert_stream/text/date.py
28
- convert_stream/text/string.py
28
+ convert_stream/text/string.py
29
+ convert_stream/text/terminal.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "convert_stream"
7
- version = "2.2.4"
7
+ version = "2.2.6"
8
8
  authors = [
9
9
  { name="Bruno Chaves"},
10
10
  ]
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env python3
2
- from .date import ConvertStringDate
3
- from .string import (
4
- ArrayString, FindText, print_line, print_title, MapText
5
- )
6
-
File without changes
File without changes