ocr-stream 2.3.3__tar.gz → 2.4__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.
- {ocr_stream-2.3.3 → ocr_stream-2.4}/PKG-INFO +2 -2
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream/__init__.py +78 -38
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream/modules/__init__.py +14 -7
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream/ocr/__init__.py +84 -10
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream/recognize.py +0 -1
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream.egg-info/PKG-INFO +2 -2
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream.egg-info/requires.txt +1 -1
- {ocr_stream-2.3.3 → ocr_stream-2.4}/pyproject.toml +2 -2
- {ocr_stream-2.3.3 → ocr_stream-2.4}/README.md +0 -0
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream/bin_tess/__init__.py +0 -0
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream.egg-info/SOURCES.txt +0 -0
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream.egg-info/dependency_links.txt +0 -0
- {ocr_stream-2.3.3 → ocr_stream-2.4}/ocr_stream.egg-info/top_level.txt +0 -0
- {ocr_stream-2.3.3 → ocr_stream-2.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ocr_stream
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4
|
|
4
4
|
Summary: Extrair textos de documentos digitalizados e imagens.
|
|
5
5
|
Author: Bruno Chaves
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -12,7 +12,7 @@ Requires-Dist: pandas
|
|
|
12
12
|
Requires-Dist: requests>=2.32.4
|
|
13
13
|
Requires-Dist: opencv-python
|
|
14
14
|
Requires-Dist: pytesseract
|
|
15
|
-
Requires-Dist: convert_stream>=2.
|
|
15
|
+
Requires-Dist: convert_stream>=2.4
|
|
16
16
|
Requires-Dist: soup_files>=1.4
|
|
17
17
|
|
|
18
18
|
# ocrlib
|
|
@@ -1,38 +1,75 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from io import BytesIO
|
|
4
|
+
import threading
|
|
4
5
|
from ocr_stream.modules import *
|
|
5
6
|
from ocr_stream.bin_tess import BinTesseract, get_path_tesseract_sys
|
|
6
7
|
from ocr_stream.ocr import TesseractOcr, TextRecognized
|
|
7
8
|
from ocr_stream.recognize import RecognizeImage, RecognizePdf
|
|
8
|
-
from convert_stream import DocumentPdf
|
|
9
|
-
from convert_stream.image import ImageObject
|
|
9
|
+
from convert_stream import DocumentPdf, PageDocumentPdf
|
|
10
|
+
from convert_stream.image import ImageObject, CollectionImages
|
|
10
11
|
from convert_stream.mod_types import (
|
|
11
|
-
ColumnsTable, ColumnBody, HeadCell, HeadValues,
|
|
12
|
+
ColumnsTable, ColumnBody, HeadCell, HeadValues, DictTextTable
|
|
12
13
|
)
|
|
14
|
+
|
|
13
15
|
from convert_stream.text import FindText
|
|
14
|
-
from convert_stream.pdf import ConvertPdfToImages
|
|
16
|
+
from convert_stream.pdf import ConvertPdfToImages, CollectionPagePdf
|
|
15
17
|
import pandas as pd
|
|
16
18
|
from soup_files import (
|
|
17
|
-
JsonConvert, ProgressBarAdapter, CreatePbar, Directory, File, InputFiles, LibraryDocs
|
|
19
|
+
JsonConvert, ProgressBarAdapter, ABCProgressBar, CreatePbar, Directory, File, InputFiles, LibraryDocs,
|
|
20
|
+
ProgressBarSimple
|
|
18
21
|
)
|
|
19
22
|
|
|
20
23
|
|
|
24
|
+
class VoidPbar(ABCProgressBar):
|
|
25
|
+
|
|
26
|
+
def __init__(self):
|
|
27
|
+
super().__init__()
|
|
28
|
+
|
|
29
|
+
def set_percent(self, percent: float):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
def set_text(self, text: str):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ProgressVoid(ProgressBarAdapter):
|
|
37
|
+
|
|
38
|
+
def __init__(self, progress_bar: ABCProgressBar = VoidPbar()):
|
|
39
|
+
super().__init__(progress_bar)
|
|
40
|
+
|
|
41
|
+
def update(self, percent: float, status: str = "-"):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
def update_percent(self, percent: float = 0):
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
def update_text(self, text: str = "-"):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def read_image(img: ImageObject, rec: RecognizeImage = RecognizeImage()) -> TextRecognized:
|
|
52
|
+
_txt = rec.image_recognize(img)
|
|
53
|
+
_txt.metadata = img.metadata
|
|
54
|
+
return _txt
|
|
55
|
+
|
|
56
|
+
|
|
21
57
|
def read_images(
|
|
22
58
|
images: list[ImageObject], *,
|
|
59
|
+
rec: RecognizeImage = RecognizeImage(),
|
|
23
60
|
pbar: ProgressBarAdapter = CreatePbar().get()
|
|
24
61
|
) -> DocumentPdf:
|
|
25
62
|
pbar.start()
|
|
26
63
|
print()
|
|
27
64
|
max_num = len(images)
|
|
28
65
|
pages = []
|
|
29
|
-
|
|
66
|
+
|
|
30
67
|
for idx, image in enumerate(images):
|
|
31
68
|
pbar.update(
|
|
32
69
|
((idx + 1) / max_num) * 100,
|
|
33
70
|
f'[OCR] {idx + 1} / {max_num}',
|
|
34
71
|
)
|
|
35
|
-
out =
|
|
72
|
+
out = read_image(image, rec=rec).to_page_pdf()
|
|
36
73
|
pages.append(out)
|
|
37
74
|
tmp_doc = DocumentPdf.create_from_pages(pages)
|
|
38
75
|
print()
|
|
@@ -47,18 +84,31 @@ def read_document(
|
|
|
47
84
|
) -> DocumentPdf:
|
|
48
85
|
pbar.start()
|
|
49
86
|
print()
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
87
|
+
_metadata = document.metadata
|
|
88
|
+
recognized_items: list[TextRecognized] = []
|
|
89
|
+
pages_pdf: list[PageDocumentPdf] = document.to_pages()
|
|
90
|
+
total = len(pages_pdf)
|
|
91
|
+
void_pbar = ProgressVoid()
|
|
92
|
+
for num, page in enumerate(pages_pdf):
|
|
93
|
+
pbar.update(
|
|
94
|
+
((num + 1) / total) * 100,
|
|
95
|
+
f'[OCR PDF] {num + 1}/{total} {page.metadata.name}',
|
|
96
|
+
)
|
|
97
|
+
convert: ConvertPdfToImages = ConvertPdfToImages(DocumentPdf.create_from_pages([page]))
|
|
98
|
+
convert.set_pbar(void_pbar)
|
|
99
|
+
images: list[ImageObject] = convert.to_images(dpi=dpi)
|
|
100
|
+
for im in images:
|
|
101
|
+
recognized_items.append(read_image(im))
|
|
53
102
|
print()
|
|
54
|
-
|
|
103
|
+
final_pages: list[PageDocumentPdf] = [x.to_page_pdf() for x in recognized_items]
|
|
104
|
+
final_doc: DocumentPdf = DocumentPdf.create_from_pages(final_pages)
|
|
105
|
+
final_doc.metadata = _metadata
|
|
106
|
+
return final_doc
|
|
55
107
|
|
|
56
108
|
|
|
57
109
|
class SearchableTextImage(object):
|
|
58
110
|
"""
|
|
59
111
|
|
|
60
|
-
create_void_map() -> dict[str, ColumnBody]:
|
|
61
|
-
|
|
62
112
|
return {
|
|
63
113
|
ColumnsTable.KEY.value: ColumnBody(ColumnsTable.KEY.value, ListString([])),
|
|
64
114
|
ColumnsTable.NUM_PAGE.value: ColumnBody(ColumnsTable.NUM_PAGE.value, ListString([])),
|
|
@@ -72,7 +122,7 @@ class SearchableTextImage(object):
|
|
|
72
122
|
"""
|
|
73
123
|
def __init__(self, silent: bool = False):
|
|
74
124
|
self.silent = silent
|
|
75
|
-
self.elements:
|
|
125
|
+
self.elements: DictTextTable = DictTextTable.create_void_dict()
|
|
76
126
|
|
|
77
127
|
def __repr__(self):
|
|
78
128
|
return f'SearchableTextPdf: {self.elements}'
|
|
@@ -149,7 +199,7 @@ class SearchableTextImage(object):
|
|
|
149
199
|
return pd.DataFrame.from_dict(self.elements)
|
|
150
200
|
|
|
151
201
|
def to_file_json(self, file: File):
|
|
152
|
-
"""Exporta os dados da busca para um arquivo
|
|
202
|
+
"""Exporta os dados da busca para um arquivo JSON"""
|
|
153
203
|
dt = JsonConvert.from_dict(self.elements).to_json_data()
|
|
154
204
|
dt.to_file(file)
|
|
155
205
|
|
|
@@ -186,10 +236,10 @@ class ImageFinder(object):
|
|
|
186
236
|
elif isinstance(img, BytesIO):
|
|
187
237
|
img = ImageObject(img)
|
|
188
238
|
|
|
189
|
-
if img.metadata
|
|
190
|
-
self.docs_collection[img.metadata
|
|
239
|
+
if not img.metadata.file_path.is_empty:
|
|
240
|
+
self.docs_collection[img.metadata.file_path] = img
|
|
191
241
|
else:
|
|
192
|
-
self.docs_collection[img.metadata
|
|
242
|
+
self.docs_collection[img.metadata.name] = img
|
|
193
243
|
|
|
194
244
|
def add_images(self, images: list[File] | list[ImageObject] | list[bytes] | list[BytesIO]) -> None:
|
|
195
245
|
for f in images:
|
|
@@ -224,7 +274,7 @@ class ImageFinder(object):
|
|
|
224
274
|
current_img: ImageObject = self.docs_collection[file_key]
|
|
225
275
|
txt_in_img = self.recognize.image_to_string(current_img)
|
|
226
276
|
if (txt_in_img == '') or (txt_in_img is None):
|
|
227
|
-
self.pbar.update_text(f'ERRO: {n+1} {current_img.metadata
|
|
277
|
+
self.pbar.update_text(f'ERRO: {n+1} {current_img.metadata.name}')
|
|
228
278
|
continue
|
|
229
279
|
try:
|
|
230
280
|
fd = FindText(txt_in_img, separator=separator)
|
|
@@ -235,20 +285,15 @@ class ImageFinder(object):
|
|
|
235
285
|
except Exception as err:
|
|
236
286
|
print(f'{__class__.__name__} {err}')
|
|
237
287
|
else:
|
|
238
|
-
file_path = current_img.metadata["file_path"]
|
|
239
|
-
file_name = current_img.metadata["name"]
|
|
240
|
-
dir_path = current_img.metadata["dir_path"]
|
|
241
|
-
file_type = current_img.metadata["extension"]
|
|
242
|
-
|
|
243
288
|
new_line: dict[str, str] = {
|
|
244
289
|
ColumnsTable.KEY.value: f'{idx}',
|
|
245
290
|
ColumnsTable.NUM_PAGE.value: 'nan',
|
|
246
291
|
ColumnsTable.NUM_LINE.value: f'{idx + 1}',
|
|
247
292
|
ColumnsTable.TEXT.value: math_text,
|
|
248
|
-
ColumnsTable.FILE_NAME.value:
|
|
249
|
-
ColumnsTable.FILETYPE.value:
|
|
250
|
-
ColumnsTable.FILE_PATH.value:
|
|
251
|
-
ColumnsTable.DIR.value: dir_path
|
|
293
|
+
ColumnsTable.FILE_NAME.value: current_img.metadata.file_path,
|
|
294
|
+
ColumnsTable.FILETYPE.value: current_img.metadata.extension,
|
|
295
|
+
ColumnsTable.FILE_PATH.value: current_img.metadata.dir_path,
|
|
296
|
+
ColumnsTable.DIR.value: current_img.metadata.dir_path,
|
|
252
297
|
}
|
|
253
298
|
_searchable.add_line(new_line)
|
|
254
299
|
return _searchable
|
|
@@ -280,7 +325,7 @@ class ImageFinder(object):
|
|
|
280
325
|
current_img: ImageObject = self.docs_collection[file_key]
|
|
281
326
|
txt_in_img = self.recognize.image_to_string(current_img)
|
|
282
327
|
if (txt_in_img == '') or (txt_in_img is None):
|
|
283
|
-
self.pbar.update_text(f'ERRO: {n + 1} {current_img.metadata
|
|
328
|
+
self.pbar.update_text(f'ERRO: {n + 1} {current_img.metadata.name}')
|
|
284
329
|
continue
|
|
285
330
|
try:
|
|
286
331
|
fd = FindText(txt_in_img, separator=separator)
|
|
@@ -291,20 +336,15 @@ class ImageFinder(object):
|
|
|
291
336
|
except Exception as err:
|
|
292
337
|
print(f'{__class__.__name__} {err}')
|
|
293
338
|
else:
|
|
294
|
-
file_path = current_img.metadata["file_path"]
|
|
295
|
-
file_name = current_img.metadata["name"]
|
|
296
|
-
dir_path = current_img.metadata["dir_path"]
|
|
297
|
-
file_type = current_img.metadata["extension"]
|
|
298
|
-
|
|
299
339
|
new_line: dict[str, str] = {
|
|
300
340
|
ColumnsTable.KEY.value: f'{idx}',
|
|
301
341
|
ColumnsTable.NUM_PAGE.value: 'nan',
|
|
302
342
|
ColumnsTable.NUM_LINE.value: f'{idx + 1}',
|
|
303
343
|
ColumnsTable.TEXT.value: math_text,
|
|
304
|
-
ColumnsTable.FILE_NAME.value:
|
|
305
|
-
ColumnsTable.FILETYPE.value:
|
|
306
|
-
ColumnsTable.FILE_PATH.value:
|
|
307
|
-
ColumnsTable.DIR.value: dir_path
|
|
344
|
+
ColumnsTable.FILE_NAME.value: current_img.metadata.file_path,
|
|
345
|
+
ColumnsTable.FILETYPE.value: current_img.metadata.extension,
|
|
346
|
+
ColumnsTable.FILE_PATH.value: current_img.metadata.dir_path,
|
|
347
|
+
ColumnsTable.DIR.value: current_img.metadata.dir_path,
|
|
308
348
|
}
|
|
309
349
|
_searchable.add_line(new_line)
|
|
310
350
|
return _searchable
|
|
@@ -8,11 +8,13 @@ class LibOcr(Enum):
|
|
|
8
8
|
|
|
9
9
|
PYTESSERACT = "pytesseract"
|
|
10
10
|
PYOCR = "pyocr"
|
|
11
|
+
EASYOCR = "easyocr"
|
|
11
12
|
NOT_IMPLEMENTED = "not_implemented"
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
MOD_PYTESSERACT: bool = False
|
|
15
16
|
MOD_PYOCR: bool = False
|
|
17
|
+
MOD_EASYOCR: bool = False
|
|
16
18
|
|
|
17
19
|
try:
|
|
18
20
|
from pytesseract import pytesseract, Output
|
|
@@ -27,16 +29,24 @@ try:
|
|
|
27
29
|
import pyocr.tesseract
|
|
28
30
|
MOD_PYOCR = True
|
|
29
31
|
except Exception as err:
|
|
30
|
-
print(err)
|
|
32
|
+
#print(err)
|
|
31
33
|
pyocr = object
|
|
32
|
-
#pyocr.tesseract = object
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
import easyocr
|
|
38
|
+
MOD_EASYOCR = True
|
|
39
|
+
except Exception as err:
|
|
40
|
+
easyocr = object
|
|
41
|
+
|
|
42
|
+
if MOD_PYTESSERACT and MOD_PYOCR and MOD_EASYOCR:
|
|
43
|
+
ModuleOcr: TypeAlias = Union[esasyocr, pytesseract, pyocr]
|
|
36
44
|
DEFAULT_LIB_OCR = LibOcr.PYTESSERACT
|
|
37
45
|
elif MOD_PYTESSERACT:
|
|
38
46
|
ModuleOcr: TypeAlias = Union[pytesseract]
|
|
39
47
|
DEFAULT_LIB_OCR = LibOcr.PYTESSERACT
|
|
48
|
+
elif MOD_EASYOCR:
|
|
49
|
+
ModuleOcr: TypeAlias = Union[easyocr]
|
|
40
50
|
elif MOD_PYOCR:
|
|
41
51
|
ModuleOcr: TypeAlias = Union[pyocr]
|
|
42
52
|
DEFAULT_LIB_OCR = LibOcr.PYOCR
|
|
@@ -44,6 +54,3 @@ else:
|
|
|
44
54
|
ModuleOcr: TypeAlias = None
|
|
45
55
|
DEFAULT_LIB_OCR = LibOcr.NOT_IMPLEMENTED
|
|
46
56
|
|
|
47
|
-
|
|
48
|
-
__all__ = ['LibOcr', 'DEFAULT_LIB_OCR']
|
|
49
|
-
|
|
@@ -10,19 +10,13 @@ from soup_files import File
|
|
|
10
10
|
from convert_stream import DocumentPdf, PageDocumentPdf
|
|
11
11
|
from convert_stream.mod_types.modules import DEFAULT_LIB_IMAGE, LibImage
|
|
12
12
|
from convert_stream.image import ImageObject
|
|
13
|
-
from convert_stream.mod_types import
|
|
13
|
+
from convert_stream.mod_types import MetaDataItem, MetaDataFile
|
|
14
14
|
from convert_stream.mod_types.table_types import ColumnBody
|
|
15
15
|
from ocr_stream.modules import (
|
|
16
|
-
LibOcr, DEFAULT_LIB_OCR, pytesseract, Output, pyocr,
|
|
16
|
+
LibOcr, DEFAULT_LIB_OCR, pytesseract, Output, pyocr, easyocr
|
|
17
17
|
)
|
|
18
18
|
from ocr_stream.bin_tess import BinTesseract
|
|
19
19
|
|
|
20
|
-
try:
|
|
21
|
-
import pyocr.tesseract
|
|
22
|
-
except Exception as err:
|
|
23
|
-
print(err)
|
|
24
|
-
pyocr = None
|
|
25
|
-
|
|
26
20
|
|
|
27
21
|
class TextRecognized(object):
|
|
28
22
|
"""
|
|
@@ -31,8 +25,9 @@ class TextRecognized(object):
|
|
|
31
25
|
"""
|
|
32
26
|
|
|
33
27
|
def __init__(self, bytes_recognized: bytes):
|
|
34
|
-
self.metadata:
|
|
28
|
+
self.metadata: MetaDataFile = MetaDataFile()
|
|
35
29
|
self.bytes_recognized: bytes = bytes_recognized
|
|
30
|
+
|
|
36
31
|
self.list_bad_char: list[str] = [
|
|
37
32
|
':', ',', ';', '$', '=',
|
|
38
33
|
'!', '}', '{', '(', ')',
|
|
@@ -51,7 +46,10 @@ class TextRecognized(object):
|
|
|
51
46
|
return doc.to_pages()[0]
|
|
52
47
|
|
|
53
48
|
def to_document(self) -> DocumentPdf:
|
|
54
|
-
|
|
49
|
+
tmp_doc = DocumentPdf(BytesIO(self.bytes_recognized))
|
|
50
|
+
tmp_doc.metadata.file_path = self.metadata.file_path
|
|
51
|
+
tmp_doc.metadata.dir_path = self.metadata.dir_path
|
|
52
|
+
return tmp_doc
|
|
55
53
|
|
|
56
54
|
def to_dict(self, separator: str = '\n') -> dict[str, ColumnBody]:
|
|
57
55
|
return self.to_page_pdf().to_dict(separator=separator)
|
|
@@ -138,6 +136,78 @@ class IPytesseract(ABCOcrTesseract):
|
|
|
138
136
|
return TextRecognized(bt)
|
|
139
137
|
|
|
140
138
|
|
|
139
|
+
# ======================================================================#
|
|
140
|
+
# Modulo easyocr
|
|
141
|
+
# ======================================================================#
|
|
142
|
+
class IEasyOcr(ABCOcrTesseract):
|
|
143
|
+
|
|
144
|
+
def __init__(self, bin_tess: BinTesseract, *, lang: str = 'pt', tess_data_dir: str = None):
|
|
145
|
+
super().__init__(bin_tess, lang=lang, tess_data_dir=tess_data_dir)
|
|
146
|
+
self.reader: easyocr.Reader = easyocr.Reader([self.lang], gpu=True)
|
|
147
|
+
|
|
148
|
+
def to_string(self, img: Union[File, ImageObject]) -> str:
|
|
149
|
+
if isinstance(img, File):
|
|
150
|
+
img = ImageObject(img)
|
|
151
|
+
result = self.reader.readtext(img.to_opencv())
|
|
152
|
+
text = '\n'.join([res[1] for res in result])
|
|
153
|
+
return text
|
|
154
|
+
|
|
155
|
+
def to_reconize(self, img: Union[File, ImageObject]) -> TextRecognized:
|
|
156
|
+
import cv2
|
|
157
|
+
import numpy as np
|
|
158
|
+
from PIL import Image
|
|
159
|
+
from io import BytesIO
|
|
160
|
+
from reportlab.pdfgen import canvas
|
|
161
|
+
from reportlab.lib.pagesizes import A4
|
|
162
|
+
from reportlab.lib.utils import ImageReader
|
|
163
|
+
|
|
164
|
+
# 1️⃣ Converter o objeto de entrada para imagem OpenCV
|
|
165
|
+
if isinstance(img, File):
|
|
166
|
+
img = ImageObject(img)
|
|
167
|
+
img_cv = img.to_opencv()
|
|
168
|
+
img_h, img_w = img_cv.shape[:2]
|
|
169
|
+
|
|
170
|
+
# 2️⃣ Reconhecer o texto com EasyOCR
|
|
171
|
+
results = self.reader.readtext(img_cv)
|
|
172
|
+
|
|
173
|
+
# 3️⃣ Converter a imagem para PDF (imagem de fundo)
|
|
174
|
+
buffer = BytesIO()
|
|
175
|
+
pdf = canvas.Canvas(buffer, pagesize=(img_w, img_h))
|
|
176
|
+
|
|
177
|
+
# Desenha a imagem original como fundo
|
|
178
|
+
img_pil = Image.fromarray(cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB))
|
|
179
|
+
pdf.drawImage(ImageReader(img_pil), 0, 0, width=img_w, height=img_h)
|
|
180
|
+
|
|
181
|
+
# 4️⃣ Adiciona o texto OCR como camada "invisível" sobre a imagem
|
|
182
|
+
pdf.setFont("Helvetica", 8)
|
|
183
|
+
pdf.setFillColorRGB(1, 1, 1, alpha=0) # texto invisível
|
|
184
|
+
|
|
185
|
+
for (bbox, text, conf) in results:
|
|
186
|
+
if not text.strip():
|
|
187
|
+
continue
|
|
188
|
+
# Coordenadas do bounding box (EasyOCR retorna 4 pontos)
|
|
189
|
+
(x1, y1), (x2, y2), (x3, y3), (x4, y4) = bbox
|
|
190
|
+
|
|
191
|
+
# Média da posição vertical
|
|
192
|
+
avg_y = (y1 + y2 + y3 + y4) / 4
|
|
193
|
+
|
|
194
|
+
# Posição invertida (PDF tem origem no canto inferior esquerdo)
|
|
195
|
+
y_pdf = img_h - avg_y
|
|
196
|
+
|
|
197
|
+
# Largura estimada
|
|
198
|
+
text_width = abs(x2 - x1)
|
|
199
|
+
pdf.drawString(x1, y_pdf, text)
|
|
200
|
+
|
|
201
|
+
pdf.showPage()
|
|
202
|
+
pdf.save()
|
|
203
|
+
buffer.seek(0)
|
|
204
|
+
|
|
205
|
+
# 5️⃣ Retorna como TextRecognized (bytes do PDF com texto embutido)
|
|
206
|
+
text_rec = TextRecognized(buffer.read())
|
|
207
|
+
text_rec.metadata = img.metadata if hasattr(img, "metadata") else MetaDataFile()
|
|
208
|
+
return text_rec
|
|
209
|
+
|
|
210
|
+
|
|
141
211
|
# ======================================================================#
|
|
142
212
|
# Modulo OCR pyocr
|
|
143
213
|
# ======================================================================#
|
|
@@ -202,6 +272,10 @@ class TesseractOcr(object):
|
|
|
202
272
|
md = IPytesseract(bin_tess, lang=lang, tess_data_dir=tess_data_dir)
|
|
203
273
|
elif lib_ocr == LibOcr.PYOCR:
|
|
204
274
|
md = IPyOcr(bin_tess, lang=lang, tess_data_dir=tess_data_dir)
|
|
275
|
+
elif lib_ocr == LibOcr.EASYOCR:
|
|
276
|
+
if lang is None:
|
|
277
|
+
lang = 'pt'
|
|
278
|
+
md = IEasyOcr(bin_tess, lang=lang, tess_data_dir=tess_data_dir)
|
|
205
279
|
else:
|
|
206
280
|
raise ValueError(f'{lib_ocr} is not supported')
|
|
207
281
|
return cls(md)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ocr_stream
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4
|
|
4
4
|
Summary: Extrair textos de documentos digitalizados e imagens.
|
|
5
5
|
Author: Bruno Chaves
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -12,7 +12,7 @@ Requires-Dist: pandas
|
|
|
12
12
|
Requires-Dist: requests>=2.32.4
|
|
13
13
|
Requires-Dist: opencv-python
|
|
14
14
|
Requires-Dist: pytesseract
|
|
15
|
-
Requires-Dist: convert_stream>=2.
|
|
15
|
+
Requires-Dist: convert_stream>=2.4
|
|
16
16
|
Requires-Dist: soup_files>=1.4
|
|
17
17
|
|
|
18
18
|
# ocrlib
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ocr_stream"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.4"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Bruno Chaves"},
|
|
10
10
|
]
|
|
@@ -21,7 +21,7 @@ dependencies = [
|
|
|
21
21
|
"requests>=2.32.4",
|
|
22
22
|
"opencv-python",
|
|
23
23
|
"pytesseract",
|
|
24
|
-
"convert_stream>=2.
|
|
24
|
+
"convert_stream>=2.4",
|
|
25
25
|
"soup_files>=1.4",
|
|
26
26
|
]
|
|
27
27
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|