ocr-stream 1.2__tar.gz → 1.3__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 ocr-stream might be problematic. Click here for more details.
- {ocr_stream-1.2 → ocr_stream-1.3}/PKG-INFO +8 -21
- ocr_stream-1.3/ocr_stream/_version.py +5 -0
- ocr_stream-1.3/ocr_stream/extractors.py +127 -0
- {ocr_stream-1.2 → ocr_stream-1.3}/ocr_stream/models/__init__.py +0 -1
- ocr_stream-1.3/ocr_stream/models/m_extractors.py +2 -0
- {ocr_stream-1.2 → ocr_stream-1.3}/ocr_stream/models/m_modules_ocr.py +27 -38
- {ocr_stream-1.2 → ocr_stream-1.3}/ocr_stream/modules_ocr.py +201 -163
- ocr_stream-1.3/ocr_stream/utils/__init__.py +16 -0
- {ocr_stream-1.2 → ocr_stream-1.3}/ocr_stream.egg-info/PKG-INFO +8 -21
- {ocr_stream-1.2 → ocr_stream-1.3}/ocr_stream.egg-info/SOURCES.txt +0 -2
- ocr_stream-1.3/ocr_stream.egg-info/requires.txt +9 -0
- {ocr_stream-1.2 → ocr_stream-1.3}/pyproject.toml +9 -8
- ocr_stream-1.2/ocr_stream/_version.py +0 -5
- ocr_stream-1.2/ocr_stream/extractors.py +0 -108
- ocr_stream-1.2/ocr_stream/models/m_extractors.py +0 -39
- ocr_stream-1.2/ocr_stream/utils/__init__.py +0 -13
- ocr_stream-1.2/ocr_stream.egg-info/not-zip-safe +0 -1
- ocr_stream-1.2/ocr_stream.egg-info/requires.txt +0 -9
- ocr_stream-1.2/setup.py +0 -44
- {ocr_stream-1.2 → ocr_stream-1.3}/README.md +0 -0
- {ocr_stream-1.2 → ocr_stream-1.3}/ocr_stream/__init__.py +0 -0
- {ocr_stream-1.2 → ocr_stream-1.3}/ocr_stream/__main__.py +0 -0
- {ocr_stream-1.2 → ocr_stream-1.3}/ocr_stream.egg-info/dependency_links.txt +0 -0
- {ocr_stream-1.2 → ocr_stream-1.3}/ocr_stream.egg-info/top_level.txt +0 -0
- {ocr_stream-1.2 → ocr_stream-1.3}/setup.cfg +0 -0
|
@@ -1,32 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ocr_stream
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3
|
|
4
4
|
Summary: Extrair textos de documentos digitalizados e imagens.
|
|
5
5
|
Author: Bruno Chaves
|
|
6
|
-
Requires: PyPDF2
|
|
7
|
-
Requires: PyMuPDF
|
|
8
|
-
Requires: reportlab
|
|
9
|
-
Requires: openpyxl
|
|
10
|
-
Requires: openpyxl
|
|
11
|
-
Requires: pandas
|
|
12
|
-
Requires: Pillow
|
|
13
|
-
Requires: opencv_python
|
|
14
|
-
Requires: requests
|
|
15
|
-
Requires: pytesseract
|
|
16
|
-
Requires: soup_files
|
|
17
|
-
Requires: convert_stream
|
|
18
6
|
Requires-Python: >=3.11
|
|
19
7
|
Description-Content-Type: text/markdown
|
|
20
|
-
Requires-Dist: PyPDF2
|
|
21
|
-
Requires-Dist: PyMuPDF
|
|
22
|
-
Requires-Dist: reportlab
|
|
23
|
-
Requires-Dist: openpyxl
|
|
24
|
-
Requires-Dist: pandas
|
|
25
|
-
Requires-Dist: Pillow
|
|
26
|
-
Requires-Dist: opencv-python
|
|
8
|
+
Requires-Dist: PyPDF2
|
|
9
|
+
Requires-Dist: PyMuPDF
|
|
10
|
+
Requires-Dist: reportlab
|
|
11
|
+
Requires-Dist: openpyxl
|
|
12
|
+
Requires-Dist: pandas
|
|
13
|
+
Requires-Dist: Pillow>=11.3.0
|
|
14
|
+
Requires-Dist: opencv-python
|
|
27
15
|
Requires-Dist: convert_stream
|
|
28
16
|
Requires-Dist: soup_files
|
|
29
|
-
Dynamic: requires
|
|
30
17
|
|
|
31
18
|
# ocrlib
|
|
32
19
|
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from typing import List
|
|
4
|
+
from ocr_stream.utils import (
|
|
5
|
+
File, Directory, ImageObject,
|
|
6
|
+
DataFrame, PageDocumentPdf,
|
|
7
|
+
DocumentPdf, PdfStream, LibraryPDF,
|
|
8
|
+
)
|
|
9
|
+
from ocr_stream.models import LibraryOCR
|
|
10
|
+
from ocr_stream.modules_ocr import ModuleOcr, TextRecognized, BinaryTesseract
|
|
11
|
+
from convert_stream import LibImageToPDF, ConvertPdfToImage, CreatePbar
|
|
12
|
+
from soup_files import ProgressBarAdapter
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RecognizeImage(object):
|
|
16
|
+
"""
|
|
17
|
+
Reconhecer textos em imagens com pytesseract|pyocr usando o tesseract
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, module_ocr):
|
|
21
|
+
super().__init__()
|
|
22
|
+
self.module_ocr: ModuleOcr = module_ocr
|
|
23
|
+
|
|
24
|
+
def image_content_data(self, img: ImageObject | File) -> DataFrame:
|
|
25
|
+
"""
|
|
26
|
+
Retorna uma tabela estruturada com os dados reconhecidos da imagem.
|
|
27
|
+
|
|
28
|
+
Este método extrai as informações contidas em uma imagem e as organiza em
|
|
29
|
+
um DataFrame com colunas como o texto detectado, coordenadas da caixa delimitadora,
|
|
30
|
+
nível do OCR e confiabilidade, entre outras.
|
|
31
|
+
|
|
32
|
+
Parâmetros:
|
|
33
|
+
img (ImageObject | File): A imagem a ser processada, podendo ser um objeto
|
|
34
|
+
`ImageObject` ou um arquivo `File`.
|
|
35
|
+
|
|
36
|
+
Retorna:
|
|
37
|
+
DataFrame: Uma tabela contendo os dados reconhecidos na imagem.
|
|
38
|
+
|
|
39
|
+
Lança:
|
|
40
|
+
ValueError: Se o tipo do parâmetro `img` não for `ImageObject` ou `File`.
|
|
41
|
+
|
|
42
|
+
@param img: Imagem a ser processada, podendo ser uma instância de `ImageObject`
|
|
43
|
+
ou um arquivo `File`.
|
|
44
|
+
@type img: ImageObject | File
|
|
45
|
+
|
|
46
|
+
@rtype: pandas.DataFrame
|
|
47
|
+
@return: Um DataFrame com os dados reconhecidos na imagem.
|
|
48
|
+
|
|
49
|
+
@raise ValueError: Caso o tipo de `img` não seja `ImageObject` nem `File`.
|
|
50
|
+
"""
|
|
51
|
+
if isinstance(img, File):
|
|
52
|
+
return self.module_ocr.image_content_data(ImageObject.create_from_file(img))
|
|
53
|
+
elif isinstance(img, ImageObject):
|
|
54
|
+
return self.module_ocr.image_content_data(img)
|
|
55
|
+
else:
|
|
56
|
+
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
57
|
+
|
|
58
|
+
def image_recognize(self, img: ImageObject | File) -> TextRecognized:
|
|
59
|
+
if isinstance(img, File):
|
|
60
|
+
return self.module_ocr.image_recognize(ImageObject.create_from_file(img))
|
|
61
|
+
elif isinstance(img, ImageObject):
|
|
62
|
+
return self.module_ocr.image_recognize(img)
|
|
63
|
+
else:
|
|
64
|
+
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
65
|
+
|
|
66
|
+
def image_to_string(self, img: ImageObject | File) -> str:
|
|
67
|
+
if isinstance(img, File):
|
|
68
|
+
return self.module_ocr.imag_to_string(ImageObject.create_from_file(img))
|
|
69
|
+
elif isinstance(img, ImageObject):
|
|
70
|
+
return self.module_ocr.imag_to_string(img)
|
|
71
|
+
else:
|
|
72
|
+
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def create(
|
|
76
|
+
cls,
|
|
77
|
+
library_ocr: LibraryOCR = LibraryOCR.PYTESSERACT,
|
|
78
|
+
*,
|
|
79
|
+
binary_tess: BinaryTesseract = BinaryTesseract(),
|
|
80
|
+
) -> RecognizeImage:
|
|
81
|
+
#
|
|
82
|
+
module_ocr = ModuleOcr.create(library_ocr, binary_tess=binary_tess)
|
|
83
|
+
return cls(module_ocr)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class RecognizePdf(object):
|
|
87
|
+
def __init__(
|
|
88
|
+
self,
|
|
89
|
+
recognize_image: RecognizeImage, *,
|
|
90
|
+
pbar: ProgressBarAdapter = CreatePbar().get()
|
|
91
|
+
):
|
|
92
|
+
self.recognize_image: RecognizeImage = recognize_image
|
|
93
|
+
self.pdf_to_image: ConvertPdfToImage = ConvertPdfToImage.create()
|
|
94
|
+
self.pbar: ProgressBarAdapter = pbar
|
|
95
|
+
|
|
96
|
+
def recognize_page_pdf(self, page: PageDocumentPdf) -> PageDocumentPdf:
|
|
97
|
+
"""
|
|
98
|
+
Converte a página em Imagem, reconhece o texto com OCR e
|
|
99
|
+
retorna uma nova página com o texto reconhecido.
|
|
100
|
+
"""
|
|
101
|
+
img: ImageObject = self.pdf_to_image.from_page_pdf(page)
|
|
102
|
+
text_recognized: TextRecognized = self.recognize_image.image_recognize(img)
|
|
103
|
+
return text_recognized.to_page_pdf()
|
|
104
|
+
|
|
105
|
+
def recognize_document(self, doc: DocumentPdf) -> DocumentPdf:
|
|
106
|
+
new_pages: List[PageDocumentPdf] = []
|
|
107
|
+
|
|
108
|
+
for n, page in enumerate(doc.get_pages()):
|
|
109
|
+
self.pbar.update(
|
|
110
|
+
((n+1)/doc.get_num_pages()) * 100,
|
|
111
|
+
f'Reconhecendo página PDF [{n+1} de {doc.get_num_pages()}]',
|
|
112
|
+
)
|
|
113
|
+
recognized_page: PageDocumentPdf = self.recognize_page_pdf(page)
|
|
114
|
+
new_pages.append(recognized_page)
|
|
115
|
+
return DocumentPdf(pages=new_pages)
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
def create(
|
|
119
|
+
cls,
|
|
120
|
+
library_ocr=LibraryOCR.PYTESSERACT,
|
|
121
|
+
*,
|
|
122
|
+
binary_tess: BinaryTesseract = BinaryTesseract(),
|
|
123
|
+
pbar: ProgressBarAdapter = CreatePbar().get(),
|
|
124
|
+
) -> RecognizePdf:
|
|
125
|
+
#
|
|
126
|
+
recognize_image = RecognizeImage.create(library_ocr, binary_tess=binary_tess)
|
|
127
|
+
return cls(recognize_image, pbar=pbar)
|
|
@@ -8,72 +8,61 @@ from pandas import DataFrame
|
|
|
8
8
|
from soup_files import File, Directory
|
|
9
9
|
from convert_stream import ImageObject, DocumentPdf, PageDocumentPdf, LibraryImage
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
class LibraryOCR(Enum):
|
|
12
13
|
PYTESSERACT = 'pytesseract'
|
|
13
14
|
PYOCR = 'pyocr'
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
|
|
16
17
|
class ABCTextRecognized(ABC):
|
|
17
|
-
def __init__(self, bytes_recognized:bytes):
|
|
18
|
+
def __init__(self, bytes_recognized: bytes):
|
|
18
19
|
super().__init__()
|
|
19
|
-
self.bytes_recognized:bytes = bytes_recognized
|
|
20
|
-
|
|
20
|
+
self.bytes_recognized: bytes = bytes_recognized
|
|
21
|
+
|
|
21
22
|
@abstractmethod
|
|
22
23
|
def to_string(self) -> str:
|
|
23
24
|
pass
|
|
24
|
-
|
|
25
|
+
|
|
25
26
|
@abstractmethod
|
|
26
27
|
def to_page_pdf(self) -> PageDocumentPdf:
|
|
27
28
|
pass
|
|
28
|
-
|
|
29
|
+
|
|
29
30
|
@abstractmethod
|
|
30
31
|
def to_document(self) -> DocumentPdf:
|
|
31
32
|
pass
|
|
32
|
-
|
|
33
|
+
|
|
33
34
|
@abstractmethod
|
|
34
|
-
def to_dataframe(self, separator:str='\n', column_text: str = 'TEXT') -> DataFrame:
|
|
35
|
+
def to_dataframe(self, separator: str = '\n', column_text: str = 'TEXT') -> DataFrame:
|
|
35
36
|
pass
|
|
36
|
-
|
|
37
|
+
|
|
37
38
|
@abstractmethod
|
|
38
|
-
def to_dict(self, separator:str='\n', column_text: str = 'TEXT') -> Dict[str, List[str]]:
|
|
39
|
+
def to_dict(self, separator: str = '\n', column_text: str = 'TEXT') -> Dict[str, List[str]]:
|
|
39
40
|
pass
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
|
|
42
|
+
|
|
42
43
|
#======================================================================#
|
|
43
44
|
# Abstração para o módulo que extrai o texto das imagens (OCR)
|
|
44
45
|
# pode ser implementado com pytesseract ou outros.
|
|
45
46
|
#======================================================================#
|
|
47
|
+
|
|
48
|
+
|
|
46
49
|
class ABCModuleOcr(ABC):
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
self.
|
|
50
|
-
self.
|
|
51
|
-
self.
|
|
52
|
-
|
|
50
|
+
|
|
51
|
+
def __init__(self, *, cmd_executable: File, lang: str = None, tess_data_dir: Directory = None):
|
|
52
|
+
self.cmd_executable: File = cmd_executable
|
|
53
|
+
self.lang: str = lang
|
|
54
|
+
self.tess_data_dir: Directory = tess_data_dir
|
|
55
|
+
self.current_library_ocr: LibraryOCR = None
|
|
56
|
+
|
|
53
57
|
@abstractmethod
|
|
54
|
-
def image_recognize(self, img:ImageObject) -> ABCTextRecognized:
|
|
58
|
+
def image_recognize(self, img: ImageObject) -> ABCTextRecognized:
|
|
55
59
|
pass
|
|
56
|
-
|
|
60
|
+
|
|
57
61
|
@abstractmethod
|
|
58
62
|
def image_content_data(self, img: ImageObject) -> DataFrame:
|
|
59
63
|
pass
|
|
60
|
-
|
|
64
|
+
|
|
61
65
|
@abstractmethod
|
|
62
|
-
def imag_to_string(self, img:ImageObject) -> str:
|
|
63
|
-
pass
|
|
64
|
-
|
|
65
|
-
@classmethod
|
|
66
|
-
def create(
|
|
67
|
-
cls,
|
|
68
|
-
library_ocr:LibraryOCR=LibraryOCR.PYTESSERACT,
|
|
69
|
-
*,
|
|
70
|
-
path_tesseract:File,
|
|
71
|
-
lang:str=None,
|
|
72
|
-
tess_data_dir:Directory=None,
|
|
73
|
-
) -> ABCModuleOcr:
|
|
66
|
+
def imag_to_string(self, img: ImageObject) -> str:
|
|
74
67
|
pass
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
68
|
|
|
79
|
-
|
|
@@ -3,98 +3,89 @@ from __future__ import annotations
|
|
|
3
3
|
from types import ModuleType
|
|
4
4
|
from typing import List, Dict
|
|
5
5
|
from pathlib import Path
|
|
6
|
+
from shutil import which
|
|
6
7
|
import re
|
|
7
8
|
import os
|
|
8
9
|
from pandas import DataFrame
|
|
9
10
|
from pytesseract import pytesseract, Output
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
from ocr_stream.models import (
|
|
11
13
|
ABCModuleOcr, ABCTextRecognized, LibraryOCR,
|
|
12
14
|
)
|
|
15
|
+
|
|
13
16
|
from ocr_stream.utils import (
|
|
14
17
|
PageDocumentPdf, DocumentPdf, LibraryImage, LibraryPDF,
|
|
15
|
-
ImageObject, ArrayString, DataString, File, Directory
|
|
18
|
+
ImageObject, ArrayString, DataString, File, Directory,
|
|
19
|
+
FileToTable, ColumnTable, KERNEL_TYPE,
|
|
16
20
|
)
|
|
17
21
|
|
|
22
|
+
try:
|
|
23
|
+
import pyocr
|
|
24
|
+
except Exception as e:
|
|
25
|
+
print(e)
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
def get_temp_dir(prefix=Path().home()) -> str:
|
|
21
|
-
prefix = Path().home()
|
|
22
|
-
sys_temp_dir = os.environ.get('TMP', os.path.join(prefix, 'var', 'temp'))
|
|
23
|
-
if not sys_temp_dir:
|
|
24
|
-
sys_temp_dir = os.path.join(prefix, 'var', 'temp')
|
|
25
|
-
if not os.path.exists(sys_temp_dir):
|
|
26
|
-
try:
|
|
27
|
-
os.makedirs(sys_temp_dir)
|
|
28
|
-
except Exception as e:
|
|
29
|
-
print(e)
|
|
30
|
-
os.environ["TEMP"] = sys_temp_dir
|
|
31
|
-
print('-' * 30)
|
|
32
|
-
print(f'Diretório temporário: {sys_temp_dir}')
|
|
33
|
-
print('-' * 30)
|
|
34
|
-
return sys_temp_dir
|
|
35
|
-
|
|
36
|
-
|
|
37
27
|
class TextRecognizedToi(object):
|
|
38
28
|
"""
|
|
39
29
|
Extração/Filtro de texto em documentos do tipo carta TOI.
|
|
40
30
|
"""
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
|
|
32
|
+
def __init__(self, value: str = None, *, separator: str = '\n', column_text='TEXT', file: File):
|
|
33
|
+
# Todas as linhas reconhecidas em imagem/página PDF.
|
|
43
34
|
if not isinstance(value, str):
|
|
44
35
|
raise ValueError(f'{__class__.__name__}Use: str, não {type(value)}')
|
|
45
|
-
self.text_document:str = DataString(value).to_upper().value if value is not None else None
|
|
46
|
-
self.separator:str = separator
|
|
47
|
-
self.file:File = file
|
|
48
|
-
self.column_text:str = column_text
|
|
49
|
-
|
|
36
|
+
self.text_document: str = DataString(value).to_upper().value if value is not None else None
|
|
37
|
+
self.separator: str = separator
|
|
38
|
+
self.file: File = file
|
|
39
|
+
self.column_text: str = column_text
|
|
40
|
+
|
|
50
41
|
self.pattern_line_uc_toi = r'UC:\s*\d+\s*TOI:\s*\d+'
|
|
51
42
|
self.pattern_uc = r'\b(?:UC:?|UC):?\s*(\d+)'
|
|
52
43
|
self.pattern_toi = r'\b(?:TOI?|TO):?\s*(\d+)'
|
|
53
44
|
self.pattern_localidade = r'LOCALIDADE:\s*(.*)'
|
|
54
|
-
|
|
45
|
+
|
|
55
46
|
self.words_toi = (
|
|
56
47
|
'TO]!', 'TO]', 'TOl', 'TOI', 'TOI:'
|
|
57
48
|
)
|
|
58
|
-
|
|
49
|
+
|
|
59
50
|
self.words_uc = (
|
|
60
51
|
'UE', 'UE:' 'UC', 'UC:', 'JC;'
|
|
61
52
|
)
|
|
62
|
-
|
|
53
|
+
|
|
63
54
|
def __replace_chars(self, text, char, new_char) -> str:
|
|
64
55
|
return re.sub(r'{}'.format(char), new_char, text)
|
|
65
|
-
|
|
66
|
-
def __get_match_groups(self, pattern, text:str) -> object | None:
|
|
56
|
+
|
|
57
|
+
def __get_match_groups(self, pattern, text: str) -> object | None:
|
|
67
58
|
i = re.search(pattern, text)
|
|
68
59
|
if i is None:
|
|
69
60
|
return None
|
|
70
61
|
return i.groups()
|
|
71
|
-
|
|
72
|
-
def __get_match_group(self, pattern, text:str) -> object | None:
|
|
62
|
+
|
|
63
|
+
def __get_match_group(self, pattern, text: str) -> object | None:
|
|
73
64
|
i = re.search(pattern, text)
|
|
74
65
|
if i is None:
|
|
75
66
|
return None
|
|
76
67
|
return i.group()
|
|
77
|
-
|
|
68
|
+
|
|
78
69
|
def is_null(self) -> bool:
|
|
79
70
|
if self.text_document is None:
|
|
80
71
|
return True
|
|
81
72
|
if self.text_document == '':
|
|
82
73
|
return True
|
|
83
74
|
return False
|
|
84
|
-
|
|
75
|
+
|
|
85
76
|
def to_string(self) -> str | None:
|
|
86
77
|
return DataString(self.text_document).to_upper().value if not self.is_null() else None
|
|
87
|
-
|
|
78
|
+
|
|
88
79
|
def to_list(self) -> List[str]:
|
|
89
80
|
return self.text_document.split(self.separator)
|
|
90
|
-
|
|
81
|
+
|
|
91
82
|
def to_array_string(self) -> ArrayString:
|
|
92
|
-
values:List[str] = self.to_list()
|
|
93
|
-
|
|
83
|
+
values: List[str] = self.to_list()
|
|
84
|
+
|
|
94
85
|
def to_upper(self) -> TextRecognizedToi:
|
|
95
86
|
self.text_document = self.text_document.upper()
|
|
96
87
|
return self
|
|
97
|
-
|
|
88
|
+
|
|
98
89
|
def to_dataframe(self) -> DataFrame:
|
|
99
90
|
uc = self.uc()
|
|
100
91
|
toi = self.toi()
|
|
@@ -107,8 +98,9 @@ class TextRecognizedToi(object):
|
|
|
107
98
|
toi = 'nan'
|
|
108
99
|
else:
|
|
109
100
|
toi = DataString(toi).replace_bad_chars()
|
|
110
|
-
toi = toi.replace_all('- ', '-').replace_all('_', ' ').replace_all('-', ' ').replace_all('TOI',
|
|
111
|
-
|
|
101
|
+
toi = toi.replace_all('- ', '-').replace_all('_', ' ').replace_all('-', ' ').replace_all('TOI',
|
|
102
|
+
'').value.strip()
|
|
103
|
+
|
|
112
104
|
df = DataFrame()
|
|
113
105
|
df[self.column_text] = self.to_list()
|
|
114
106
|
num = len(df)
|
|
@@ -118,7 +110,7 @@ class TextRecognizedToi(object):
|
|
|
118
110
|
df['ARQUIVO'] = [self.file.absolute()] * num
|
|
119
111
|
df['MD5'] = [self.file.md5()] * num
|
|
120
112
|
return df
|
|
121
|
-
|
|
113
|
+
|
|
122
114
|
def remove_bad_chars(self) -> TextRecognizedToi:
|
|
123
115
|
values = []
|
|
124
116
|
for item in self.to_list():
|
|
@@ -127,18 +119,18 @@ class TextRecognizedToi(object):
|
|
|
127
119
|
)
|
|
128
120
|
self.listText = values
|
|
129
121
|
return self
|
|
130
|
-
|
|
122
|
+
|
|
131
123
|
def uc(self) -> str:
|
|
132
124
|
"""
|
|
133
125
|
Extrair o número da UC em forma de string, se a operação falhar, será retornado (nan)
|
|
134
126
|
"""
|
|
135
127
|
line_uc_toi = self.line_uc_and_toi()
|
|
136
|
-
uc_value:str = None
|
|
128
|
+
uc_value: str = None
|
|
137
129
|
if line_uc_toi is not None:
|
|
138
130
|
uc_value = self.__get_match_group(self.pattern_uc, line_uc_toi)
|
|
139
131
|
if uc_value is not None:
|
|
140
132
|
return uc_value.replace('UC', '')
|
|
141
|
-
|
|
133
|
+
|
|
142
134
|
arr = ArrayString(self.text_document.split(' '))
|
|
143
135
|
for w in self.words_uc:
|
|
144
136
|
out = arr.get_next(w).value
|
|
@@ -149,16 +141,16 @@ class TextRecognizedToi(object):
|
|
|
149
141
|
else:
|
|
150
142
|
return out
|
|
151
143
|
return None
|
|
152
|
-
|
|
144
|
+
|
|
153
145
|
def toi(self) -> str:
|
|
154
146
|
line_uc_toi = self.line_uc_and_toi()
|
|
155
|
-
toi_value:str = None
|
|
147
|
+
toi_value: str = None
|
|
156
148
|
if line_uc_toi is not None:
|
|
157
149
|
toi_value = self.__get_match_group(self.pattern_toi, line_uc_toi)
|
|
158
150
|
if toi_value is not None:
|
|
159
151
|
return toi_value.replace('TOI', '')
|
|
160
152
|
arr = ArrayString(self.text_document.split(' '))
|
|
161
|
-
|
|
153
|
+
|
|
162
154
|
for w in self.words_toi:
|
|
163
155
|
out = arr.get_next(w).value
|
|
164
156
|
try:
|
|
@@ -168,7 +160,7 @@ class TextRecognizedToi(object):
|
|
|
168
160
|
else:
|
|
169
161
|
return out
|
|
170
162
|
return None
|
|
171
|
-
|
|
163
|
+
|
|
172
164
|
def roteiro(self) -> str:
|
|
173
165
|
self.remove_bad_chars()
|
|
174
166
|
pass
|
|
@@ -184,10 +176,10 @@ class TextRecognizedToi(object):
|
|
|
184
176
|
loc = DataString(loc).replace_all(' ').value
|
|
185
177
|
# Remover "_" do final
|
|
186
178
|
return re.sub(r"_$", "", loc)
|
|
187
|
-
|
|
179
|
+
|
|
188
180
|
def line_postagem(self) -> str:
|
|
189
181
|
pass
|
|
190
|
-
|
|
182
|
+
|
|
191
183
|
def line_uc_and_toi(self) -> DataString | None:
|
|
192
184
|
line_toi = None
|
|
193
185
|
lines = self.to_list()
|
|
@@ -198,12 +190,13 @@ class TextRecognizedToi(object):
|
|
|
198
190
|
line_toi = out
|
|
199
191
|
break
|
|
200
192
|
return line_toi
|
|
201
|
-
|
|
193
|
+
|
|
202
194
|
def line_roteiro(self) -> DataString:
|
|
203
|
-
return DataString(None)
|
|
195
|
+
return DataString(None)
|
|
196
|
+
|
|
197
|
+
#======================================================================#
|
|
204
198
|
|
|
205
199
|
|
|
206
|
-
#======================================================================#
|
|
207
200
|
# Texto reconhecido de uma imagem.
|
|
208
201
|
#======================================================================#
|
|
209
202
|
|
|
@@ -216,66 +209,112 @@ class TextRecognized(ABCTextRecognized):
|
|
|
216
209
|
-> str
|
|
217
210
|
-> PageDocumentPdf()
|
|
218
211
|
"""
|
|
212
|
+
|
|
219
213
|
def __init__(self, bytes_recognized: bytes):
|
|
220
214
|
super().__init__(bytes_recognized)
|
|
221
|
-
|
|
215
|
+
|
|
222
216
|
self.list_bad_char: List[str] = [
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
'¢', '“', '\'', '¢', '"',
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
217
|
+
':', ',', ';', '$', '=',
|
|
218
|
+
'!', '}', '{', '(', ')',
|
|
219
|
+
'|', '\\', '‘', '*'
|
|
220
|
+
'¢', '“', '\'', '¢', '"',
|
|
221
|
+
'#', '.', '<', '?', '>',
|
|
222
|
+
'»', '@', '+', '[', ']',
|
|
223
|
+
'%', '~', '¥', '♀',
|
|
230
224
|
]
|
|
231
|
-
|
|
225
|
+
|
|
232
226
|
def to_string(self) -> str | None:
|
|
233
227
|
return self.to_page_pdf().to_string()
|
|
234
|
-
|
|
228
|
+
|
|
235
229
|
def to_page_pdf(self) -> PageDocumentPdf:
|
|
236
230
|
_page = PageDocumentPdf.create_from_page_bytes(
|
|
237
|
-
self.bytes_recognized,
|
|
238
|
-
library
|
|
231
|
+
self.bytes_recognized,
|
|
232
|
+
library=LibraryPDF.FITZ
|
|
239
233
|
)
|
|
240
234
|
return _page
|
|
241
|
-
|
|
235
|
+
|
|
242
236
|
def to_document(self) -> DocumentPdf:
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
237
|
+
return DocumentPdf(pages=[self.to_page_pdf()])
|
|
238
|
+
|
|
239
|
+
def to_dict(
|
|
240
|
+
self,
|
|
241
|
+
separator='\n',
|
|
242
|
+
column_text: ColumnTable.TEXT = ColumnTable.TEXT
|
|
243
|
+
) -> Dict[str, List[str]]:
|
|
244
|
+
#
|
|
245
|
+
image_dict: Dict[str, List[str]] = {
|
|
246
|
+
column_text.value: [],
|
|
247
|
+
ColumnTable.NUMLINHA.value: [],
|
|
250
248
|
}
|
|
251
|
-
image_text:str = self.to_string()
|
|
249
|
+
image_text: str = self.to_string()
|
|
252
250
|
if (image_text is None) or (image_text == ''):
|
|
253
251
|
return {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
column_text.value: ['nan'],
|
|
253
|
+
ColumnTable.NUMLINHA.value: ['nan'],
|
|
254
|
+
}
|
|
255
|
+
|
|
258
256
|
image_lines: List[str] = image_text.split(separator)
|
|
259
257
|
for num, line in enumerate(image_lines):
|
|
260
|
-
image_dict[column_text].append(line)
|
|
261
|
-
image_dict[
|
|
262
|
-
return image_dict
|
|
263
|
-
|
|
264
|
-
def to_dataframe(self, separator
|
|
258
|
+
image_dict[column_text.value].append(line)
|
|
259
|
+
image_dict[ColumnTable.NUMLINHA.value].append(f'{num + 1}')
|
|
260
|
+
return image_dict
|
|
261
|
+
|
|
262
|
+
def to_dataframe(self, separator='\n', column_text: ColumnTable.TEXT = ColumnTable.TEXT) -> DataFrame:
|
|
265
263
|
return DataFrame(self.to_dict(separator, column_text))
|
|
266
|
-
|
|
267
|
-
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class BinaryTesseract(object):
|
|
267
|
+
"""
|
|
268
|
+
Fornece o caminho absoluto do tesseract instalado no sistema, se
|
|
269
|
+
disponível. Você pode usar um binário alternativo, basta informar
|
|
270
|
+
o caminho do binário desejado no construtor.
|
|
271
|
+
"""
|
|
272
|
+
def __init__(
|
|
273
|
+
self,
|
|
274
|
+
path: File = None, *,
|
|
275
|
+
lang: str = None,
|
|
276
|
+
tess_data_dir: Directory = None
|
|
277
|
+
):
|
|
278
|
+
#
|
|
279
|
+
self.tess_data_dir: Directory = tess_data_dir
|
|
280
|
+
self.lang: str = lang
|
|
281
|
+
self.path_tesseract: File = path
|
|
282
|
+
if self.path_tesseract is None:
|
|
283
|
+
if KERNEL_TYPE == 'Windows':
|
|
284
|
+
name = 'tesseract.exe'
|
|
285
|
+
else:
|
|
286
|
+
name = 'tesseract'
|
|
287
|
+
output = which(name)
|
|
288
|
+
if output is not None:
|
|
289
|
+
if os.path.isfile(output):
|
|
290
|
+
print(f'[binary]: {output}')
|
|
291
|
+
self.path_tesseract = File(output)
|
|
292
|
+
|
|
293
|
+
def exists(self) -> bool:
|
|
294
|
+
if self.path_tesseract is None:
|
|
295
|
+
return False
|
|
296
|
+
return True
|
|
297
|
+
|
|
298
|
+
|
|
268
299
|
#======================================================================#
|
|
269
300
|
# Modulo OCR pytesseract
|
|
270
301
|
#======================================================================#
|
|
271
302
|
|
|
272
|
-
|
|
273
|
-
|
|
303
|
+
|
|
304
|
+
class IPytesseract(ABCModuleOcr):
|
|
305
|
+
|
|
306
|
+
def __init__(
|
|
307
|
+
self, *,
|
|
308
|
+
cmd_executable: File,
|
|
309
|
+
lang: str = None,
|
|
310
|
+
tess_data_dir: Directory = None,
|
|
311
|
+
):
|
|
312
|
+
#
|
|
274
313
|
super().__init__(cmd_executable=cmd_executable, lang=lang, tess_data_dir=tess_data_dir)
|
|
275
|
-
self.current_library:LibraryOCR = LibraryOCR.PYTESSERACT
|
|
276
|
-
self._pyTesseract:pytesseract = pytesseract
|
|
314
|
+
self.current_library: LibraryOCR = LibraryOCR.PYTESSERACT
|
|
315
|
+
self._pyTesseract: pytesseract = pytesseract
|
|
277
316
|
self._pyTesseract.tesseract_cmd = self.cmd_executable.absolute()
|
|
278
|
-
|
|
317
|
+
|
|
279
318
|
def __get_tess_dir_config(self) -> str | None:
|
|
280
319
|
"""
|
|
281
320
|
https://github.com/h/pytesseract
|
|
@@ -292,143 +331,142 @@ class IModulePytesseract(ABCModuleOcr):
|
|
|
292
331
|
if not self.tess_data_dir.path.exists():
|
|
293
332
|
return ''
|
|
294
333
|
return r'--tessdata-dir "{}"'.format(self.tess_data_dir.absolute())
|
|
295
|
-
|
|
334
|
+
|
|
296
335
|
def imag_to_string(self, img) -> str:
|
|
297
336
|
if img.current_library == LibraryImage.OPENCV:
|
|
298
|
-
text_img:str = self._pyTesseract.image_to_string(
|
|
337
|
+
text_img: str = self._pyTesseract.image_to_string(
|
|
299
338
|
img.to_image_opencv(),
|
|
300
339
|
lang=self.lang,
|
|
301
340
|
config=self.__get_tess_dir_config()
|
|
302
341
|
)
|
|
303
342
|
else:
|
|
304
|
-
text_img:str = self._pyTesseract.image_to_string(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
343
|
+
text_img: str = self._pyTesseract.image_to_string(
|
|
344
|
+
img.to_image_pil(),
|
|
345
|
+
lang=self.lang,
|
|
346
|
+
config=self.__get_tess_dir_config()
|
|
347
|
+
)
|
|
309
348
|
return text_img
|
|
310
|
-
|
|
349
|
+
|
|
311
350
|
def image_recognize(self, img) -> TextRecognized:
|
|
351
|
+
"""
|
|
352
|
+
|
|
353
|
+
@rtype: TextRecognized
|
|
354
|
+
"""
|
|
312
355
|
if img.current_library == LibraryImage.OPENCV:
|
|
313
|
-
pdf_bytes:bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
356
|
+
pdf_bytes: bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
314
357
|
img.to_image_opencv(),
|
|
315
358
|
lang=self.lang,
|
|
316
359
|
config=self.__get_tess_dir_config()
|
|
317
360
|
)
|
|
318
361
|
else:
|
|
319
|
-
pdf_bytes:bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
362
|
+
pdf_bytes: bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
363
|
+
img.to_image_pil(),
|
|
364
|
+
lang=self.lang,
|
|
365
|
+
config=self.__get_tess_dir_config()
|
|
366
|
+
)
|
|
324
367
|
return TextRecognized(pdf_bytes)
|
|
325
|
-
|
|
326
|
-
def image_content_data(self, img) -> DataFrame:
|
|
368
|
+
|
|
369
|
+
def image_content_data(self, img: ImageObject) -> DataFrame:
|
|
370
|
+
"""
|
|
371
|
+
Retorna um dataframe gerado por pytesseract
|
|
372
|
+
|
|
373
|
+
@rtype: DataFrame
|
|
374
|
+
"""
|
|
327
375
|
if img.current_library == LibraryImage.OPENCV:
|
|
328
|
-
text_data:DataFrame = self._pyTesseract.image_to_data(
|
|
376
|
+
text_data: DataFrame = self._pyTesseract.image_to_data(
|
|
329
377
|
img.to_image_opencv(),
|
|
330
378
|
lang=self.lang,
|
|
331
379
|
config=self.__get_tess_dir_config(),
|
|
332
380
|
output_type=Output.DATAFRAME,
|
|
333
381
|
)
|
|
334
382
|
else:
|
|
335
|
-
text_data:DataFrame = self._pyTesseract.image_to_data(
|
|
383
|
+
text_data: DataFrame = self._pyTesseract.image_to_data(
|
|
336
384
|
img.to_image_pil(),
|
|
337
385
|
lang=self.lang,
|
|
338
386
|
config=self.__get_tess_dir_config(),
|
|
339
387
|
output_type=Output.DATAFRAME,
|
|
340
388
|
)
|
|
341
389
|
return text_data
|
|
342
|
-
|
|
343
|
-
|
|
390
|
+
|
|
391
|
+
|
|
344
392
|
#======================================================================#
|
|
345
393
|
# Modulo OCR pyocr
|
|
346
394
|
#======================================================================#
|
|
347
395
|
|
|
348
|
-
|
|
349
|
-
|
|
396
|
+
|
|
397
|
+
class IPyOcr(ABCModuleOcr):
|
|
398
|
+
def __init__(self, *, cmd_executable, lang=None, tess_data_dir=None):
|
|
350
399
|
super().__init__(cmd_executable=cmd_executable, lang=lang, tess_data_dir=tess_data_dir)
|
|
351
|
-
self.current_library:LibraryOCR = LibraryOCR.PYOCR
|
|
352
|
-
self.cmd_executable:File = cmd_executable
|
|
353
|
-
self.tess_data_dir:Directory = tess_data_dir
|
|
400
|
+
self.current_library: LibraryOCR = LibraryOCR.PYOCR
|
|
401
|
+
self.cmd_executable: File = cmd_executable
|
|
402
|
+
self.tess_data_dir: Directory = tess_data_dir
|
|
354
403
|
try:
|
|
355
404
|
import pyocr
|
|
356
405
|
import pyocr.tesseract
|
|
357
406
|
except Exception as e:
|
|
358
|
-
raise
|
|
359
|
-
|
|
360
|
-
pyocr_modules:List[ModuleType] = pyocr.get_available_tools()
|
|
407
|
+
raise e
|
|
408
|
+
|
|
409
|
+
pyocr_modules: List[ModuleType] = pyocr.get_available_tools()
|
|
361
410
|
if len(pyocr_modules) == 0:
|
|
362
411
|
raise ValueError(f"{__class__.__name__} No OCR tool found")
|
|
363
412
|
# The tools are returned in the recommended order of usage
|
|
364
|
-
self._pyOcr:pyocr.tesseract = pyocr_modules[0]
|
|
365
|
-
langs:List[str] = self._pyOcr.get_available_languages()
|
|
413
|
+
self._pyOcr: pyocr.tesseract = pyocr_modules[0]
|
|
414
|
+
langs: List[str] = self._pyOcr.get_available_languages()
|
|
366
415
|
if lang in lang:
|
|
367
416
|
self.lang = lang
|
|
368
417
|
else:
|
|
369
418
|
self.lang = langs[0]
|
|
370
|
-
|
|
419
|
+
|
|
371
420
|
# Ex: Will use tool 'libtesseract'
|
|
372
421
|
print(f"Will use tool {self._pyOcr.get_name()}")
|
|
373
|
-
|
|
422
|
+
|
|
374
423
|
def imag_to_string(self, img) -> str:
|
|
375
424
|
return self._pyOcr.image_to_string(
|
|
376
425
|
img.to_image_pil(),
|
|
377
426
|
lang=self.lang,
|
|
378
427
|
builder=pyocr.builders.TextBuilder()
|
|
379
428
|
)
|
|
380
|
-
|
|
429
|
+
|
|
381
430
|
def image_recognize(self, img) -> TextRecognized:
|
|
382
431
|
raise NotImplementedError(f'{__class__.__name__} método não implementado')
|
|
383
|
-
|
|
432
|
+
|
|
384
433
|
def image_content_data(self, img) -> DataFrame:
|
|
385
434
|
raise NotImplementedError(f'{__class__.__name__} método não implementado')
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
class ModuleOcr(
|
|
389
|
-
def __init__(self, module_ocr:
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
lang=module_ocr.lang,
|
|
393
|
-
tess_data_dir=module_ocr.tess_data_dir
|
|
394
|
-
)
|
|
395
|
-
self.module_ocr:ABCModuleOcr = module_ocr
|
|
396
|
-
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
class ModuleOcr(object):
|
|
438
|
+
def __init__(self, module_ocr: IPytesseract | IPyOcr):
|
|
439
|
+
self.module_ocr: IPytesseract | IPyOcr = module_ocr
|
|
440
|
+
|
|
397
441
|
def image_content_data(self, img: ImageObject) -> DataFrame:
|
|
398
442
|
return self.module_ocr.image_content_data(img)
|
|
399
|
-
|
|
400
|
-
def image_recognize(self, img:ImageObject) -> TextRecognized:
|
|
443
|
+
|
|
444
|
+
def image_recognize(self, img: ImageObject) -> TextRecognized:
|
|
401
445
|
return self.module_ocr.image_recognize(img)
|
|
402
|
-
|
|
446
|
+
|
|
403
447
|
def imag_to_string(self, img) -> str:
|
|
404
448
|
return self.module_ocr.imag_to_string(img)
|
|
405
|
-
|
|
449
|
+
|
|
406
450
|
@classmethod
|
|
407
451
|
def create(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
tess_data_dir = None
|
|
414
|
-
) -> ModuleOcr:
|
|
452
|
+
cls,
|
|
453
|
+
library_ocr=LibraryOCR.PYTESSERACT,
|
|
454
|
+
*,
|
|
455
|
+
binary_tess: BinaryTesseract = BinaryTesseract(),
|
|
456
|
+
) -> ModuleOcr:
|
|
415
457
|
#
|
|
416
458
|
if library_ocr == LibraryOCR.PYTESSERACT:
|
|
417
|
-
_module_ocr =
|
|
459
|
+
_module_ocr = IPytesseract(
|
|
460
|
+
cmd_executable=binary_tess.path_tesseract,
|
|
461
|
+
lang=binary_tess.lang,
|
|
462
|
+
tess_data_dir=binary_tess.tess_data_dir,
|
|
463
|
+
)
|
|
418
464
|
elif library_ocr == LibraryOCR.PYOCR:
|
|
419
|
-
_module_ocr =
|
|
465
|
+
_module_ocr = IPyOcr(
|
|
466
|
+
cmd_executable=binary_tess.path_tesseract,
|
|
467
|
+
lang=binary_tess.lang,
|
|
468
|
+
tess_data_dir=binary_tess.tess_data_dir,
|
|
469
|
+
)
|
|
420
470
|
else:
|
|
421
471
|
raise NotImplementedError(f'{__class__.__name__}\nLibraryOcr não implementada: {library_ocr}')
|
|
422
472
|
return cls(_module_ocr)
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
from pandas import DataFrame
|
|
4
|
+
from soup_files import (
|
|
5
|
+
File, Directory, UserAppDir, UserFileSystem,
|
|
6
|
+
InputFiles, JsonConvert, JsonData, LibraryDocs,
|
|
7
|
+
KERNEL_TYPE,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from convert_stream import (
|
|
11
|
+
LibraryDates, LibraryImage, LibraryPDF, LibImageToPDF, LibConvertPDF,
|
|
12
|
+
ImageObject, PdfStream, ImageStream, PageDocumentPdf, DocumentPdf,
|
|
13
|
+
ArrayString, DataString, print_line, print_title, FileToTable,
|
|
14
|
+
)
|
|
15
|
+
from convert_stream.models import ConvertStringDate
|
|
16
|
+
from convert_stream.table_files import ColumnTable
|
|
@@ -1,32 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ocr_stream
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3
|
|
4
4
|
Summary: Extrair textos de documentos digitalizados e imagens.
|
|
5
5
|
Author: Bruno Chaves
|
|
6
|
-
Requires: PyPDF2
|
|
7
|
-
Requires: PyMuPDF
|
|
8
|
-
Requires: reportlab
|
|
9
|
-
Requires: openpyxl
|
|
10
|
-
Requires: openpyxl
|
|
11
|
-
Requires: pandas
|
|
12
|
-
Requires: Pillow
|
|
13
|
-
Requires: opencv_python
|
|
14
|
-
Requires: requests
|
|
15
|
-
Requires: pytesseract
|
|
16
|
-
Requires: soup_files
|
|
17
|
-
Requires: convert_stream
|
|
18
6
|
Requires-Python: >=3.11
|
|
19
7
|
Description-Content-Type: text/markdown
|
|
20
|
-
Requires-Dist: PyPDF2
|
|
21
|
-
Requires-Dist: PyMuPDF
|
|
22
|
-
Requires-Dist: reportlab
|
|
23
|
-
Requires-Dist: openpyxl
|
|
24
|
-
Requires-Dist: pandas
|
|
25
|
-
Requires-Dist: Pillow
|
|
26
|
-
Requires-Dist: opencv-python
|
|
8
|
+
Requires-Dist: PyPDF2
|
|
9
|
+
Requires-Dist: PyMuPDF
|
|
10
|
+
Requires-Dist: reportlab
|
|
11
|
+
Requires-Dist: openpyxl
|
|
12
|
+
Requires-Dist: pandas
|
|
13
|
+
Requires-Dist: Pillow>=11.3.0
|
|
14
|
+
Requires-Dist: opencv-python
|
|
27
15
|
Requires-Dist: convert_stream
|
|
28
16
|
Requires-Dist: soup_files
|
|
29
|
-
Dynamic: requires
|
|
30
17
|
|
|
31
18
|
# ocrlib
|
|
32
19
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
README.md
|
|
2
2
|
pyproject.toml
|
|
3
|
-
setup.py
|
|
4
3
|
ocr_stream/__init__.py
|
|
5
4
|
ocr_stream/__main__.py
|
|
6
5
|
ocr_stream/_version.py
|
|
@@ -9,7 +8,6 @@ ocr_stream/modules_ocr.py
|
|
|
9
8
|
ocr_stream.egg-info/PKG-INFO
|
|
10
9
|
ocr_stream.egg-info/SOURCES.txt
|
|
11
10
|
ocr_stream.egg-info/dependency_links.txt
|
|
12
|
-
ocr_stream.egg-info/not-zip-safe
|
|
13
11
|
ocr_stream.egg-info/requires.txt
|
|
14
12
|
ocr_stream.egg-info/top_level.txt
|
|
15
13
|
ocr_stream/models/__init__.py
|
|
@@ -4,22 +4,23 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ocr_stream"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.3"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Bruno Chaves"},
|
|
10
10
|
]
|
|
11
|
+
|
|
11
12
|
description = "Extrair textos de documentos digitalizados e imagens."
|
|
12
13
|
readme = "README.md"
|
|
13
14
|
requires-python = ">=3.11"
|
|
14
15
|
|
|
15
16
|
dependencies = [
|
|
16
|
-
"PyPDF2
|
|
17
|
-
"PyMuPDF
|
|
18
|
-
"reportlab
|
|
19
|
-
"openpyxl
|
|
20
|
-
"pandas
|
|
21
|
-
"Pillow
|
|
22
|
-
"opencv-python
|
|
17
|
+
"PyPDF2",
|
|
18
|
+
"PyMuPDF",
|
|
19
|
+
"reportlab",
|
|
20
|
+
"openpyxl",
|
|
21
|
+
"pandas",
|
|
22
|
+
"Pillow>=11.3.0",
|
|
23
|
+
"opencv-python",
|
|
23
24
|
"convert_stream",
|
|
24
25
|
"soup_files",
|
|
25
26
|
]
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
from ocr_stream.utils import (
|
|
4
|
-
File, Directory, ImageObject,
|
|
5
|
-
DataFrame, PageDocumentPdf,
|
|
6
|
-
DocumentPdf, PdfStream, LibraryPDF,
|
|
7
|
-
)
|
|
8
|
-
from ocr_stream.models import ABCRecognizeImage, LibraryOCR
|
|
9
|
-
from ocr_stream.modules_ocr import ModuleOcr, TextRecognized
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class RecognizeImage(ABCRecognizeImage):
|
|
13
|
-
def __init__(self, module_ocr):
|
|
14
|
-
super().__init__(module_ocr)
|
|
15
|
-
|
|
16
|
-
def image_content_data(self, img: ImageObject | File) -> DataFrame:
|
|
17
|
-
if isinstance(img, File):
|
|
18
|
-
return self.module_ocr.image_content_data(ImageObject.create_from_file(img))
|
|
19
|
-
elif isinstance(img, ImageObject):
|
|
20
|
-
return self.module_ocr.image_content_data(img)
|
|
21
|
-
else:
|
|
22
|
-
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
23
|
-
|
|
24
|
-
def image_recognize(self, img: ImageObject | File) -> TextRecognized:
|
|
25
|
-
if isinstance(img, File):
|
|
26
|
-
return self.module_ocr.image_recognize(ImageObject.create_from_file(img))
|
|
27
|
-
elif isinstance(img, ImageObject):
|
|
28
|
-
return self.module_ocr.image_recognize(img)
|
|
29
|
-
else:
|
|
30
|
-
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
31
|
-
|
|
32
|
-
def image_to_string(self, img: ImageObject | File) -> str:
|
|
33
|
-
if isinstance(img, File):
|
|
34
|
-
return self.module_ocr.imag_to_string(ImageObject.create_from_file(img))
|
|
35
|
-
elif isinstance(img, ImageObject):
|
|
36
|
-
return self.module_ocr.imag_to_string(img)
|
|
37
|
-
else:
|
|
38
|
-
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
39
|
-
|
|
40
|
-
@classmethod
|
|
41
|
-
def create(
|
|
42
|
-
cls,
|
|
43
|
-
library_ocr = LibraryOCR.PYTESSERACT,
|
|
44
|
-
*,
|
|
45
|
-
path_tesseract,
|
|
46
|
-
lang=None,
|
|
47
|
-
tess_data_dir=None
|
|
48
|
-
) -> RecognizeImage:
|
|
49
|
-
#
|
|
50
|
-
module_ocr: ModuleOcr = ModuleOcr.create(
|
|
51
|
-
library_ocr,
|
|
52
|
-
path_tesseract=path_tesseract,
|
|
53
|
-
lang=lang,
|
|
54
|
-
tess_data_dir=tess_data_dir
|
|
55
|
-
)
|
|
56
|
-
return cls(module_ocr)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class RecognizePdf(object):
|
|
60
|
-
def __init__(self, recognize_image: RecognizeImage):
|
|
61
|
-
self.recognize_image: RecognizeImage = recognize_image
|
|
62
|
-
|
|
63
|
-
def recognize_page_pdf(self, page:PageDocumentPdf) -> PageDocumentPdf:
|
|
64
|
-
"""
|
|
65
|
-
Converte a página em Imagem, reconhece o texto com OCR e
|
|
66
|
-
retorna uma nova página com o texto reconhecido.
|
|
67
|
-
"""
|
|
68
|
-
pdf_stream = PdfStream(library_pdf=LibraryPDF.FITZ)
|
|
69
|
-
pdf_stream.add_page(page)
|
|
70
|
-
img: ImageObject = pdf_stream.to_images()[0]
|
|
71
|
-
text_recognized:TextRecognized = self.recognize_image.image_recognize(img)
|
|
72
|
-
return text_recognized.to_page_pdf()
|
|
73
|
-
|
|
74
|
-
def recognize_document(self, doc:DocumentPdf) -> DocumentPdf:
|
|
75
|
-
new: DocumentPdf = DocumentPdf()
|
|
76
|
-
for page in doc.pages:
|
|
77
|
-
recognized_page: PageDocumentPdf = self.recognize_page_pdf(page)
|
|
78
|
-
new.add_page(recognized_page)
|
|
79
|
-
return new
|
|
80
|
-
|
|
81
|
-
@classmethod
|
|
82
|
-
def create(
|
|
83
|
-
cls,
|
|
84
|
-
library_ocr = LibraryOCR.PYTESSERACT,
|
|
85
|
-
*,
|
|
86
|
-
path_tesseract: File,
|
|
87
|
-
lang:str=None,
|
|
88
|
-
tess_data_dir: Directory=None,
|
|
89
|
-
) -> RecognizePdf:
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
recognize_image = RecognizeImage.create(
|
|
93
|
-
library_ocr,
|
|
94
|
-
path_tesseract=path_tesseract,
|
|
95
|
-
lang=lang,
|
|
96
|
-
tess_data_dir=tess_data_dir
|
|
97
|
-
)
|
|
98
|
-
return cls(recognize_image)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
#
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
from abc import ABC, abstractmethod
|
|
5
|
-
|
|
6
|
-
from pandas import DataFrame
|
|
7
|
-
from soup_files import File, Directory
|
|
8
|
-
from convert_stream import ImageObject
|
|
9
|
-
from ocr_stream.models.m_modules_ocr import ABCModuleOcr, ABCTextRecognized, LibraryOCR
|
|
10
|
-
|
|
11
|
-
class ABCRecognizeImage(ABC):
|
|
12
|
-
def __init__(self, module_ocr:ABCModuleOcr):
|
|
13
|
-
super().__init__()
|
|
14
|
-
self.module_ocr:ABCModuleOcr = module_ocr
|
|
15
|
-
|
|
16
|
-
@abstractmethod
|
|
17
|
-
def image_to_string(self, img:ImageObject | File) -> str:
|
|
18
|
-
pass
|
|
19
|
-
|
|
20
|
-
@abstractmethod
|
|
21
|
-
def image_recognize(self, img:ImageObject | File) -> ABCTextRecognized:
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
|
-
@abstractmethod
|
|
25
|
-
def image_content_data(self, img:ImageObject | File) -> DataFrame:
|
|
26
|
-
pass
|
|
27
|
-
|
|
28
|
-
@classmethod
|
|
29
|
-
def create(
|
|
30
|
-
cls,
|
|
31
|
-
library_ocr:LibraryOCR = LibraryOCR.PYTESSERACT,
|
|
32
|
-
*,
|
|
33
|
-
path_tesseract:File,
|
|
34
|
-
lang:str=None,
|
|
35
|
-
tess_data_dir:Directory=None
|
|
36
|
-
) -> ABCRecognizeImage:
|
|
37
|
-
pass
|
|
38
|
-
|
|
39
|
-
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
#
|
|
3
|
-
from pandas import DataFrame
|
|
4
|
-
from soup_files import (
|
|
5
|
-
File, Directory, UserAppDir, UserFileSystem, InputFiles,
|
|
6
|
-
JsonConvert, JsonData
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
from convert_stream import (
|
|
10
|
-
LibraryDates, LibraryImage, LibraryPDF, ImageObject,
|
|
11
|
-
PdfStream, ImageStream,PageDocumentPdf, DocumentPdf,
|
|
12
|
-
ArrayString, DataString, ConvertDate, print_line, print_title
|
|
13
|
-
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
ocr_stream-1.2/setup.py
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
|
-
|
|
6
|
-
try:
|
|
7
|
-
from setuptools import setup
|
|
8
|
-
except Exception as e:
|
|
9
|
-
print(e)
|
|
10
|
-
sys.exit(1)
|
|
11
|
-
|
|
12
|
-
file_setup = os.path.abspath(os.path.realpath(__file__))
|
|
13
|
-
dir_of_project = os.path.dirname(file_setup)
|
|
14
|
-
sys.path.insert(0, dir_of_project)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
DESCRIPTION = ''
|
|
18
|
-
LONG_DESCRIPTION = ''
|
|
19
|
-
|
|
20
|
-
setup(
|
|
21
|
-
name='ocrlib',
|
|
22
|
-
version='1.2',
|
|
23
|
-
description=DESCRIPTION,
|
|
24
|
-
long_description=LONG_DESCRIPTION,
|
|
25
|
-
license='MIT',
|
|
26
|
-
requires=[
|
|
27
|
-
'PyPDF2',
|
|
28
|
-
'PyMuPDF',
|
|
29
|
-
'reportlab',
|
|
30
|
-
'openpyxl',
|
|
31
|
-
'openpyxl',
|
|
32
|
-
'pandas',
|
|
33
|
-
'Pillow',
|
|
34
|
-
'opencv_python',
|
|
35
|
-
'requests',
|
|
36
|
-
'pytesseract',
|
|
37
|
-
'soup_files',
|
|
38
|
-
'convert_stream',
|
|
39
|
-
],
|
|
40
|
-
packages=['ocrlib', 'ocrlib.models', 'ocrlib.utils'],
|
|
41
|
-
zip_safe=False,
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|