convert-stream 2.2.1__tar.gz → 2.2.5__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.
Potentially problematic release.
This version of convert-stream might be problematic. Click here for more details.
- {convert_stream-2.2.1 → convert_stream-2.2.5}/PKG-INFO +1 -1
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/pdf/pdf_document.py +238 -93
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/stream.py +12 -8
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/table_files.py +8 -101
- convert_stream-2.2.5/convert_stream/text/__init__.py +7 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/text/string.py +0 -25
- convert_stream-2.2.5/convert_stream/text/terminal.py +61 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream.egg-info/PKG-INFO +1 -1
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream.egg-info/SOURCES.txt +2 -1
- {convert_stream-2.2.1 → convert_stream-2.2.5}/pyproject.toml +1 -1
- convert_stream-2.2.1/convert_stream/text/__init__.py +0 -6
- {convert_stream-2.2.1 → convert_stream-2.2.5}/README.md +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/__init__.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/__main__.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/_version.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/enum_libs/enums.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/enum_libs/modules.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/image/__init__.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/image/img_object.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/pdf/__init__.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/pdf/image_to_pdf.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/pdf/pdf_page.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/pdf/pdf_to_image.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/sheets/__init__.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/sheets/load.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/sheets/parse.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/sheets/save.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream/text/date.py +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream.egg-info/dependency_links.txt +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream.egg-info/requires.txt +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/convert_stream.egg-info/top_level.txt +0 -0
- {convert_stream-2.2.1 → convert_stream-2.2.5}/setup.cfg +0 -0
|
@@ -6,13 +6,107 @@
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
from abc import ABC, abstractmethod
|
|
8
8
|
from io import BytesIO
|
|
9
|
-
|
|
10
|
-
|
|
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):
|
|
@@ -39,11 +133,11 @@ class ABCDocument(ABC):
|
|
|
39
133
|
pass
|
|
40
134
|
|
|
41
135
|
@abstractmethod
|
|
42
|
-
def add_page(self, page:
|
|
136
|
+
def add_page(self, page: PageDocumentPdf):
|
|
43
137
|
pass
|
|
44
138
|
|
|
45
139
|
@abstractmethod
|
|
46
|
-
def add_pages(self, pages: list[
|
|
140
|
+
def add_pages(self, pages: list[PageDocumentPdf]):
|
|
47
141
|
pass
|
|
48
142
|
|
|
49
143
|
@abstractmethod
|
|
@@ -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:
|
|
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,22 +180,29 @@ 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
|
|
183
|
+
_page_pdf = PageDocumentPdf.create_from_page_fitz(pg)
|
|
98
184
|
return _page_pdf
|
|
99
185
|
|
|
100
186
|
def get_number_pages(self) -> int:
|
|
101
187
|
return self.mod_doc_pdf.page_count
|
|
102
188
|
|
|
103
|
-
def add_page(self, page:
|
|
189
|
+
def add_page(self, page: PageDocumentPdf):
|
|
104
190
|
# Assume que page.mod_page é fitz.Page
|
|
105
|
-
self.mod_doc_pdf.insert_pdf(
|
|
191
|
+
self.mod_doc_pdf.insert_pdf(
|
|
192
|
+
page.implement_page_pdf.mod_page.parent,
|
|
193
|
+
from_page=page.implement_page_pdf.mod_page.number,
|
|
194
|
+
to_page=page.implement_page_pdf.mod_page.number
|
|
195
|
+
)
|
|
106
196
|
|
|
107
|
-
def add_pages(self, pages: list[
|
|
197
|
+
def add_pages(self, pages: list[PageDocumentPdf]):
|
|
108
198
|
for page in pages:
|
|
109
199
|
self.add_page(page)
|
|
110
200
|
|
|
111
201
|
def to_file(self, file: File):
|
|
112
|
-
|
|
202
|
+
try:
|
|
203
|
+
self.mod_doc_pdf.save(file.path)
|
|
204
|
+
except Exception as e:
|
|
205
|
+
show_warning(f'{e}')
|
|
113
206
|
|
|
114
207
|
def to_bytes(self) -> BytesIO:
|
|
115
208
|
buf = BytesIO()
|
|
@@ -124,27 +217,10 @@ class ImplementDocumentFitz(ABCDocument):
|
|
|
124
217
|
pages.append(page_pdf)
|
|
125
218
|
return pages
|
|
126
219
|
|
|
127
|
-
def to_list(self, separator: str = '\n') -> list[str]:
|
|
128
|
-
pages: list[PageDocumentPdf] = self.to_pages()
|
|
129
|
-
values = []
|
|
130
|
-
for pg in pages:
|
|
131
|
-
values.extend(pg.to_list(separator))
|
|
132
|
-
return values
|
|
133
|
-
|
|
134
|
-
def to_dict(self, separator: str = '\n') -> dict[str, list[str]]:
|
|
135
|
-
pages_pdf = self.to_pages()
|
|
136
|
-
document_dict = PageDocumentPdf.DEFAULT_DICT
|
|
137
|
-
for pg in pages_pdf:
|
|
138
|
-
page_dict = pg.to_dict(separator)
|
|
139
|
-
document_dict['TEXTO'].extend(page_dict['TEXTO'])
|
|
140
|
-
document_dict['NUM_PAGE'].extend(page_dict['NUM_PAGE'])
|
|
141
|
-
document_dict['NUM_LINHA'].extend(page_dict['NUM_LINHA'])
|
|
142
|
-
return document_dict
|
|
143
|
-
|
|
144
220
|
@classmethod
|
|
145
221
|
def create_from_bytes(cls, bt: BytesIO) -> ImplementDocumentFitz:
|
|
146
222
|
# Cria documento a partir de BytesIO
|
|
147
|
-
doc = fitz.open(stream=bt.getvalue(), filetype="pdf")
|
|
223
|
+
doc: ModuleDocPdf = fitz.open(stream=bt.getvalue(), filetype="pdf")
|
|
148
224
|
name = get_hash_from_bytes(bt)
|
|
149
225
|
return cls(doc, name)
|
|
150
226
|
|
|
@@ -156,7 +232,6 @@ class ImplementDocumentFitz(ABCDocument):
|
|
|
156
232
|
|
|
157
233
|
@classmethod
|
|
158
234
|
def create_from_pages(cls, pages: list[PageDocumentPdf]) -> ImplementDocumentFitz:
|
|
159
|
-
|
|
160
235
|
pdf_document = fitz.Document() # Criar novo documento PDF.
|
|
161
236
|
for page in pages:
|
|
162
237
|
# Verifica se a página é do tipo fitz.Page
|
|
@@ -168,13 +243,7 @@ class ImplementDocumentFitz(ABCDocument):
|
|
|
168
243
|
from_page=page.implement_page_pdf.mod_page.number,
|
|
169
244
|
to_page=page.implement_page_pdf.mod_page.number
|
|
170
245
|
)
|
|
171
|
-
|
|
172
246
|
bt = BytesIO(pdf_document.write())
|
|
173
|
-
#name = get_hash_from_bytes(bt)
|
|
174
|
-
#bt.seek(0)
|
|
175
|
-
#bt.close()
|
|
176
|
-
#del bt
|
|
177
|
-
#return cls(pdf_document, name)
|
|
178
247
|
return cls.create_from_bytes(bt)
|
|
179
248
|
|
|
180
249
|
|
|
@@ -215,10 +284,10 @@ class ImplementDocumentPyPdf(ABCDocument):
|
|
|
215
284
|
def get_number_pages(self) -> int:
|
|
216
285
|
return len(self.mod_doc_pdf.pages)
|
|
217
286
|
|
|
218
|
-
def add_page(self, page:
|
|
219
|
-
self.mod_doc_pdf.add_page(page)
|
|
287
|
+
def add_page(self, page: PageDocumentPdf):
|
|
288
|
+
self.mod_doc_pdf.add_page(page.implement_page_pdf.mod_page)
|
|
220
289
|
|
|
221
|
-
def add_pages(self, pages: list[
|
|
290
|
+
def add_pages(self, pages: list[PageDocumentPdf]):
|
|
222
291
|
for page in pages:
|
|
223
292
|
self.add_page(page)
|
|
224
293
|
|
|
@@ -239,23 +308,6 @@ class ImplementDocumentPyPdf(ABCDocument):
|
|
|
239
308
|
pages_pdf.append(pg)
|
|
240
309
|
return pages_pdf
|
|
241
310
|
|
|
242
|
-
def to_list(self, separator: str = '\n') -> list[str]:
|
|
243
|
-
pages: list[PageDocumentPdf] = self.to_pages()
|
|
244
|
-
values = []
|
|
245
|
-
for pg in pages:
|
|
246
|
-
values.extend(pg.to_list(separator))
|
|
247
|
-
return values
|
|
248
|
-
|
|
249
|
-
def to_dict(self, separator: str = '\n') -> dict[str, list[str]]:
|
|
250
|
-
pages_pdf = self.to_pages()
|
|
251
|
-
document_dict = PageDocumentPdf.DEFAULT_DICT
|
|
252
|
-
for pg in pages_pdf:
|
|
253
|
-
page_dict = pg.to_dict(separator)
|
|
254
|
-
document_dict['TEXTO'].extend(page_dict['TEXTO'])
|
|
255
|
-
document_dict['NUM_PAGE'].extend(page_dict['NUM_PAGE'])
|
|
256
|
-
document_dict['NUM_LINHA'].extend(page_dict['NUM_LINHA'])
|
|
257
|
-
return document_dict
|
|
258
|
-
|
|
259
311
|
@classmethod
|
|
260
312
|
def create_from_bytes(cls, bt: BytesIO) -> ImplementDocumentPyPdf:
|
|
261
313
|
# Usa PdfReader diretamente de BytesIO
|
|
@@ -266,7 +318,6 @@ class ImplementDocumentPyPdf(ABCDocument):
|
|
|
266
318
|
pdf_writer = PdfWriter()
|
|
267
319
|
for page in reader.pages:
|
|
268
320
|
pdf_writer.add_page(page)
|
|
269
|
-
|
|
270
321
|
bt.close()
|
|
271
322
|
del bt
|
|
272
323
|
del reader
|
|
@@ -327,10 +378,10 @@ class DocumentPdf(object):
|
|
|
327
378
|
def get_number_pages(self) -> int:
|
|
328
379
|
return self.doc_pdf.get_number_pages()
|
|
329
380
|
|
|
330
|
-
def add_page(self, page:
|
|
381
|
+
def add_page(self, page: PageDocumentPdf):
|
|
331
382
|
self.doc_pdf.add_page(page)
|
|
332
383
|
|
|
333
|
-
def add_pages(self, pages: list[
|
|
384
|
+
def add_pages(self, pages: list[PageDocumentPdf]):
|
|
334
385
|
self.doc_pdf.add_pages(pages)
|
|
335
386
|
|
|
336
387
|
def to_file(self, file: File):
|
|
@@ -343,36 +394,130 @@ class DocumentPdf(object):
|
|
|
343
394
|
return self.doc_pdf.to_pages()
|
|
344
395
|
|
|
345
396
|
def to_list(self, separator: str = '\n') -> list[str]:
|
|
346
|
-
|
|
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
|
|
347
405
|
|
|
348
406
|
def to_dict(self, separator: str = '\n') -> dict[str, list[str]]:
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
page_text_str = pg.find(text_find, separator=separator, iqual=iqual, case=case)
|
|
356
|
-
if page_text_str is not None:
|
|
357
|
-
_find_item = page_text_str
|
|
358
|
-
break
|
|
359
|
-
pages.clear()
|
|
360
|
-
del pages
|
|
361
|
-
return _find_item
|
|
362
|
-
|
|
363
|
-
def find_all(self, text: str, *, separator: str = '\n', iqual: bool = False, case: bool = True) -> list[str]:
|
|
364
|
-
if text is None:
|
|
365
|
-
raise ValueError(f'{__class__.__name__}: o texto de pesquisa {text} é nulo!')
|
|
366
|
-
elements = []
|
|
407
|
+
dict_doc = {
|
|
408
|
+
ColumnsTable.NUM_PAGE.value: [],
|
|
409
|
+
ColumnsTable.NUM_LINHA.value: [],
|
|
410
|
+
ColumnsTable.TEXT.value: [],
|
|
411
|
+
ColumnsTable.FILENAME.value: [],
|
|
412
|
+
}
|
|
367
413
|
pages = self.to_pages()
|
|
368
|
-
for
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
|
376
521
|
|
|
377
522
|
@classmethod
|
|
378
523
|
def create_from_bytes(cls, bt: BytesIO, *, lib_pdf: LibPDF = LibPDF.FITZ) -> DocumentPdf:
|
|
@@ -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 =
|
|
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
|
|
64
|
+
def is_empty(self) -> bool:
|
|
65
65
|
return self.collection_pages.is_null
|
|
66
66
|
|
|
67
67
|
def set_land_scape(self):
|
|
@@ -79,7 +79,7 @@ class PdfStream(object):
|
|
|
79
79
|
self.collection_pages.add_page(page)
|
|
80
80
|
|
|
81
81
|
def add_pages(self, pages: list[PageDocumentPdf]) -> None:
|
|
82
|
-
self.add_pages(pages)
|
|
82
|
+
self.collection_pages.add_pages(pages)
|
|
83
83
|
|
|
84
84
|
def add_file_image(self, f: File) -> None:
|
|
85
85
|
self.collection_images.add_file_image(f)
|
|
@@ -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
|
-
|
|
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
|
|
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,
|
|
13
|
-
from convert_stream.
|
|
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
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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():
|
|
@@ -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}')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|