ocr-stream 2.4.1__tar.gz → 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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ocr_stream
3
- Version: 2.4.1
3
+ Version: 2.5
4
4
  Summary: Extrair textos de documentos digitalizados e imagens.
5
5
  Author: Bruno Chaves
6
6
  Requires-Python: >=3.11
@@ -12,8 +12,8 @@ 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.4.1
16
- Requires-Dist: soup_files>=1.4
15
+ Requires-Dist: convert_stream>=2.5
16
+ Requires-Dist: soup_files>=1.4.2
17
17
 
18
18
  # ocrlib
19
19
 
@@ -4,27 +4,31 @@ from io import BytesIO
4
4
  from ocr_stream.modules import *
5
5
  from ocr_stream.bin_tess import BinTesseract, get_path_tesseract_sys
6
6
  from ocr_stream.ocr import TesseractOcr, TextRecognized
7
- from ocr_stream.recognize import (
8
- RecognizeImage, RecognizePdf, VoidPbar, ProgressVoid
7
+ from ocr_stream.recognize import RecognizeImage, RecognizePdf
8
+ from convert_stream import DocumentPdf
9
+ from convert_stream.image import ImageObject
10
+ from sheet_stream import (
11
+ ColumnsTable, HeadValues, HeadCell, TableDocuments
9
12
  )
10
- import convert_stream as cs
13
+ from convert_stream.text.find_text import FindText
11
14
  import pandas as pd
12
- import soup_files as sp
13
-
14
- __version__ = '2.4'
15
+ from soup_files import (
16
+ JsonConvert, ProgressBarAdapter, CreatePbar,
17
+ Directory, File, InputFiles, LibraryDocs
18
+ )
15
19
 
16
20
 
17
- def read_image(img: cs.ImageObject, rec: RecognizeImage = RecognizeImage()) -> TextRecognized:
21
+ def read_image(img: ImageObject, rec: RecognizeImage = RecognizeImage()) -> TextRecognized:
18
22
  _txt = rec.image_recognize(img)
19
23
  _txt.metadata = img.metadata
20
24
  return _txt
21
25
 
22
26
 
23
27
  def read_images(
24
- images: list[cs.ImageObject], *,
28
+ images: list[ImageObject], *,
25
29
  rec: RecognizeImage = RecognizeImage(),
26
- pbar: sp.ProgressBarAdapter = sp.CreatePbar().get()
27
- ) -> cs.DocumentPdf:
30
+ pbar: ProgressBarAdapter = CreatePbar().get()
31
+ ) -> DocumentPdf:
28
32
  pbar.start()
29
33
  print()
30
34
  max_num = len(images)
@@ -33,76 +37,55 @@ def read_images(
33
37
  for idx, image in enumerate(images):
34
38
  pbar.update(
35
39
  ((idx + 1) / max_num) * 100,
36
- f'[OCR IMAGENS] {idx + 1} / {max_num}',
40
+ f'[OCR Imagem] {idx + 1} / {max_num}',
37
41
  )
38
42
  out = read_image(image, rec=rec).to_page_pdf()
39
43
  pages.append(out)
40
- tmp_doc = cs.DocumentPdf.create_from_pages(pages)
41
- print()
44
+ tmp_doc = DocumentPdf.create_from_pages(pages)
42
45
  pbar.stop()
43
46
  return tmp_doc
44
47
 
45
48
 
46
49
  def read_document(
47
- document: cs.DocumentPdf, *,
48
- dpi: int = 300,
49
- pbar: sp.ProgressBarAdapter = sp.CreatePbar().get()
50
- ) -> cs.DocumentPdf:
51
- pbar.start()
52
- print()
53
- _metadata: cs.MetaDataFile = document.metadata
54
- recognized_items: list[TextRecognized] = []
55
- pages_pdf: list[cs.PageDocumentPdf] = document.to_pages()
56
- total = len(pages_pdf)
57
- void_pbar = ProgressVoid()
58
- for num, page in enumerate(pages_pdf):
59
- pbar.update(
60
- ((num + 1) / total) * 100,
61
- f'[OCR PDF] {num + 1}/{total} {page.metadata.name}',
62
- )
63
- convert: cs.ConvertPdfToImages = cs.ConvertPdfToImages(cs.DocumentPdf.create_from_pages([page]))
64
- convert.set_pbar(void_pbar)
65
- images: list[cs.ImageObject] = convert.to_images(dpi=dpi)
66
- for im in images:
67
- recognized_items.append(read_image(im))
68
- print()
69
- final_pages: list[cs.PageDocumentPdf] = [x.to_page_pdf() for x in recognized_items]
70
- final_doc: cs.DocumentPdf = cs.DocumentPdf.create_from_pages(final_pages)
71
- final_doc.metadata = _metadata
72
- return final_doc
50
+ document: DocumentPdf, *,
51
+ dpi: int = 200,
52
+ rec: RecognizePdf = RecognizePdf(),
53
+ ) -> DocumentPdf:
54
+ rec.pbar.start()
55
+ return rec.recognize_document(document, dpi=dpi)
73
56
 
74
57
 
75
58
  class SearchableTextImage(object):
76
59
  """
77
60
 
78
61
  return {
79
- cs.ColumnsTable.KEY.value: cs.ColumnBody(cs.ColumnsTable.KEY.value, ListString([])),
80
- cs.ColumnsTable.NUM_PAGE.value: cs.ColumnBody(cs.ColumnsTable.NUM_PAGE.value, ListString([])),
81
- cs.ColumnsTable.NUM_LINE.value: cs.ColumnBody(cs.ColumnsTable.NUM_LINE.value, ListString([])),
82
- cs.ColumnsTable.TEXT.value: cs.ColumnBody(cs.ColumnsTable.TEXT.value, ListString([])),
83
- cs.ColumnsTable.FILE_NAME.value: cs.ColumnBody(cs.ColumnsTable.FILE_NAME.value, ListString([])),
84
- cs.ColumnsTable.FILETYPE.value: cs.ColumnBody(cs.ColumnsTable.FILETYPE.value, ListString([])),
85
- cs.ColumnsTable.FILE_PATH.value: cs.ColumnBody(cs.ColumnsTable.FILE_PATH.value, ListString([])),
86
- cs.ColumnsTable.DIR.value: cs.ColumnBody(cs.ColumnsTable.DIR.value, ListString([])),
62
+ ColumnsTable.KEY.value: ColumnBody(ColumnsTable.KEY.value, ListString([])),
63
+ ColumnsTable.NUM_PAGE.value: ColumnBody(ColumnsTable.NUM_PAGE.value, ListString([])),
64
+ ColumnsTable.NUM_LINE.value: ColumnBody(ColumnsTable.NUM_LINE.value, ListString([])),
65
+ ColumnsTable.TEXT.value: ColumnBody(ColumnsTable.TEXT.value, ListString([])),
66
+ ColumnsTable.FILE_NAME.value: ColumnBody(ColumnsTable.FILE_NAME.value, ListString([])),
67
+ ColumnsTable.FILETYPE.value: ColumnBody(ColumnsTable.FILETYPE.value, ListString([])),
68
+ ColumnsTable.FILE_PATH.value: ColumnBody(ColumnsTable.FILE_PATH.value, ListString([])),
69
+ ColumnsTable.DIR.value: ColumnBody(ColumnsTable.DIR.value, ListString([])),
87
70
  }
88
71
  """
89
72
  def __init__(self, silent: bool = False):
90
73
  self.silent = silent
91
- self.elements: cs.DictTextTable = cs.DictTextTable.create_void_dict()
74
+ self.elements: TableDocuments = TableDocuments.create_void_dict()
92
75
 
93
76
  def __repr__(self):
94
77
  return f'SearchableTextPdf: {self.elements}'
95
78
 
96
79
  @property
97
80
  def length(self) -> int:
98
- return len(self.elements[cs.ColumnsTable.TEXT.value])
81
+ return len(self.elements[ColumnsTable.TEXT.value])
99
82
 
100
83
  def is_empty(self) -> bool:
101
- return len(self.elements[cs.ColumnsTable.TEXT.value]) == 0
84
+ return len(self.elements[ColumnsTable.TEXT.value]) == 0
102
85
 
103
86
  @property
104
- def columns(self) -> cs.HeadValues:
105
- return cs.HeadValues([cs.HeadCell(x) for x in list(self.elements.keys())])
87
+ def columns(self) -> HeadValues:
88
+ return HeadValues([HeadCell(x) for x in list(self.elements.keys())])
106
89
 
107
90
  @property
108
91
  def first(self) -> dict[str, str]:
@@ -140,8 +123,8 @@ class SearchableTextImage(object):
140
123
  return _current_item
141
124
 
142
125
  def add_line(self, line: dict[str, str]) -> None:
143
- cols: cs.HeadValues = self.columns
144
- cols_line: cs.HeadValues = cs.HeadValues([cs.HeadCell(y) for y in list(line.keys())])
126
+ cols: HeadValues = self.columns
127
+ cols_line: HeadValues = HeadValues([HeadCell(y) for y in list(line.keys())])
145
128
  for col in cols:
146
129
  if cols_line.contains(col, case=True, iqual=True):
147
130
  self.elements[col].append(line[col])
@@ -156,7 +139,7 @@ class SearchableTextImage(object):
156
139
  ou 'nas' em caso de erro nas = Not a String
157
140
  """
158
141
  try:
159
- return ' '.join(self.elements[cs.ColumnsTable.TEXT.value])
142
+ return ' '.join(self.elements[ColumnsTable.TEXT.value])
160
143
  except Exception as e:
161
144
  print(e)
162
145
  return 'nas'
@@ -164,12 +147,12 @@ class SearchableTextImage(object):
164
147
  def to_data_frame(self) -> pd.DataFrame:
165
148
  return pd.DataFrame.from_dict(self.elements)
166
149
 
167
- def to_file_json(self, file: sp.File):
150
+ def to_file_json(self, file: File):
168
151
  """Exporta os dados da busca para um arquivo JSON"""
169
- dt = sp.JsonConvert.from_dict(self.elements).to_json_data()
152
+ dt = JsonConvert.from_dict(self.elements).to_json_data()
170
153
  dt.to_file(file)
171
154
 
172
- def to_file_excel(self, file: sp.File):
155
+ def to_file_excel(self, file: File):
173
156
  """Exporta os dados da busca para um arquivo .XLSX"""
174
157
  self.to_data_frame().to_excel(file.absolute(), index=False)
175
158
 
@@ -180,9 +163,9 @@ class ImageFinder(object):
180
163
  """
181
164
 
182
165
  def __init__(self):
183
- self.docs_collection: dict[str, cs.ImageObject] = {}
166
+ self.docs_collection: dict[str, ImageObject] = {}
184
167
  self.recognize: RecognizeImage = RecognizeImage()
185
- self.pbar: sp.ProgressBarAdapter = sp.ProgressBarAdapter()
168
+ self.pbar: ProgressBarAdapter = ProgressBarAdapter()
186
169
 
187
170
  def is_empty(self) -> bool:
188
171
  return len(self.docs_collection) == 0
@@ -190,29 +173,29 @@ class ImageFinder(object):
190
173
  def clear(self) -> None:
191
174
  self.docs_collection.clear()
192
175
 
193
- def add_image(self, img: sp.File | bytes | BytesIO | str | cs.ImageObject) -> None:
194
- if isinstance(img, sp.File):
195
- img = cs.ImageObject(img)
196
- elif isinstance(img, cs.ImageObject):
176
+ def add_image(self, img: File | bytes | BytesIO | str | ImageObject) -> None:
177
+ if isinstance(img, File):
178
+ img = ImageObject(img)
179
+ elif isinstance(img, ImageObject):
197
180
  pass
198
181
  elif isinstance(img, bytes):
199
- img = cs.ImageObject(img)
182
+ img = ImageObject(img)
200
183
  elif isinstance(img, str):
201
- img = cs.ImageObject(img)
184
+ img = ImageObject(img)
202
185
  elif isinstance(img, BytesIO):
203
- img = cs.ImageObject(img)
186
+ img = ImageObject(img)
204
187
 
205
188
  if not img.metadata.file_path.is_empty:
206
189
  self.docs_collection[img.metadata.file_path] = img
207
190
  else:
208
191
  self.docs_collection[img.metadata.name] = img
209
192
 
210
- def add_images(self, images: list[sp.File] | list[cs.ImageObject] | list[bytes] | list[BytesIO]) -> None:
193
+ def add_images(self, images: list[File] | list[ImageObject] | list[bytes] | list[BytesIO]) -> None:
211
194
  for f in images:
212
195
  self.add_image(f)
213
196
 
214
- def add_directory_images(self, dir_pdf: sp.Directory) -> None:
215
- files = sp.InputFiles(dir_pdf).get_files(file_type=sp.LibraryDocs.IMAGE)
197
+ def add_directory_images(self, dir_pdf: Directory) -> None:
198
+ files = InputFiles(dir_pdf).get_files(file_type=LibraryDocs.IMAGE)
216
199
  if len(files) > 0:
217
200
  self.add_images(files)
218
201
 
@@ -237,13 +220,13 @@ class ImageFinder(object):
237
220
  f'[PESQUISANDO]: {n+1}/{total_num}',
238
221
  )
239
222
 
240
- current_img: cs.ImageObject = self.docs_collection[file_key]
223
+ current_img: ImageObject = self.docs_collection[file_key]
241
224
  txt_in_img = self.recognize.image_to_string(current_img)
242
225
  if (txt_in_img == '') or (txt_in_img is None):
243
226
  self.pbar.update_text(f'ERRO: {n+1} {current_img.metadata.name}')
244
227
  continue
245
228
  try:
246
- fd = cs.text.FindText(txt_in_img, separator=separator)
229
+ fd = FindText(txt_in_img, separator=separator)
247
230
  idx = fd.find_index(text, iqual=iqual, case=case)
248
231
  if idx is None:
249
232
  continue
@@ -252,14 +235,14 @@ class ImageFinder(object):
252
235
  print(f'{__class__.__name__} {err}')
253
236
  else:
254
237
  new_line: dict[str, str] = {
255
- cs.ColumnsTable.KEY.value: f'{idx}',
256
- cs.ColumnsTable.NUM_PAGE.value: 'nan',
257
- cs.ColumnsTable.NUM_LINE.value: f'{idx + 1}',
258
- cs.ColumnsTable.TEXT.value: math_text,
259
- cs.ColumnsTable.FILE_NAME.value: current_img.metadata.file_path,
260
- cs.ColumnsTable.FILETYPE.value: current_img.metadata.extension,
261
- cs.ColumnsTable.FILE_PATH.value: current_img.metadata.dir_path,
262
- cs.ColumnsTable.DIR.value: current_img.metadata.dir_path,
238
+ ColumnsTable.KEY: f'{idx}',
239
+ ColumnsTable.NUM_PAGE: 'nan',
240
+ ColumnsTable.NUM_LINE: f'{idx + 1}',
241
+ ColumnsTable.TEXT: math_text,
242
+ ColumnsTable.FILE_NAME: current_img.metadata.file_path,
243
+ ColumnsTable.FILETYPE: current_img.metadata.extension,
244
+ ColumnsTable.FILE_PATH: current_img.metadata.dir_path,
245
+ ColumnsTable.DIR: current_img.metadata.dir_path,
263
246
  }
264
247
  _searchable.add_line(new_line)
265
248
  return _searchable
@@ -288,13 +271,13 @@ class ImageFinder(object):
288
271
  f'[PESQUISANDO]: {n + 1}/{total_num}',
289
272
  )
290
273
 
291
- current_img: cs.ImageObject = self.docs_collection[file_key]
274
+ current_img: ImageObject = self.docs_collection[file_key]
292
275
  txt_in_img = self.recognize.image_to_string(current_img)
293
276
  if (txt_in_img == '') or (txt_in_img is None):
294
277
  self.pbar.update_text(f'ERRO: {n + 1} {current_img.metadata.name}')
295
278
  continue
296
279
  try:
297
- fd = cs.text.FindText(txt_in_img, separator=separator)
280
+ fd = FindText(txt_in_img, separator=separator)
298
281
  idx = fd.find_index(text, iqual=iqual, case=case)
299
282
  if idx is None:
300
283
  continue
@@ -303,14 +286,14 @@ class ImageFinder(object):
303
286
  print(f'{__class__.__name__} {err}')
304
287
  else:
305
288
  new_line: dict[str, str] = {
306
- cs.ColumnsTable.KEY.value: f'{idx}',
307
- cs.ColumnsTable.NUM_PAGE.value: 'nan',
308
- cs.ColumnsTable.NUM_LINE.value: f'{idx + 1}',
309
- cs.ColumnsTable.TEXT.value: math_text,
310
- cs.ColumnsTable.FILE_NAME.value: current_img.metadata.file_path,
311
- cs.ColumnsTable.FILETYPE.value: current_img.metadata.extension,
312
- cs.ColumnsTable.FILE_PATH.value: current_img.metadata.dir_path,
313
- cs.ColumnsTable.DIR.value: current_img.metadata.dir_path,
289
+ ColumnsTable.KEY: f'{idx}',
290
+ ColumnsTable.NUM_PAGE: 'nan',
291
+ ColumnsTable.NUM_LINE: f'{idx + 1}',
292
+ ColumnsTable.TEXT: math_text,
293
+ ColumnsTable.FILE_NAME: current_img.metadata.file_path,
294
+ ColumnsTable.FILETYPE: current_img.metadata.extension,
295
+ ColumnsTable.FILE_PATH: current_img.metadata.dir_path,
296
+ ColumnsTable.DIR: current_img.metadata.dir_path,
314
297
  }
315
298
  _searchable.add_line(new_line)
316
299
  return _searchable
@@ -318,5 +301,5 @@ class ImageFinder(object):
318
301
 
319
302
  __all__ = [
320
303
  'ImageFinder', 'SearchableTextImage', 'read_images',
321
- 'read_document', 'RecognizeImage', 'RecognizePdf', 'VoidPbar', 'ProgressVoid'
304
+ 'read_document', 'RecognizeImage', 'RecognizePdf', 'LibOcr',
322
305
  ]
@@ -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,25 @@ 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
34
 
33
35
 
34
- if MOD_PYTESSERACT and MOD_PYOCR:
35
- ModuleOcr: TypeAlias = Union[pyocr, pytesseract]
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]
50
+ DEFAULT_LIB_OCR = LibOcr.EASYOCR
40
51
  elif MOD_PYOCR:
41
52
  ModuleOcr: TypeAlias = Union[pyocr]
42
53
  DEFAULT_LIB_OCR = LibOcr.PYOCR
@@ -44,5 +55,3 @@ else:
44
55
  ModuleOcr: TypeAlias = None
45
56
  DEFAULT_LIB_OCR = LibOcr.NOT_IMPLEMENTED
46
57
 
47
-
48
- __all__ = ['LibOcr', 'DEFAULT_LIB_OCR']
@@ -4,24 +4,23 @@ from __future__ import annotations
4
4
  import os.path
5
5
  from abc import abstractmethod, ABC
6
6
  from typing import Union
7
- from io import BytesIO
8
7
  from pandas import DataFrame
9
8
  from soup_files import File
10
- from convert_stream import DocumentPdf, PageDocumentPdf
9
+ from convert_stream import DocumentPdf, PageDocumentPdf, DictTextTable
11
10
  from convert_stream.mod_types.modules import DEFAULT_LIB_IMAGE, LibImage
12
11
  from convert_stream.image import ImageObject
13
- from convert_stream.mod_types import MetaDataItem, MetaDataFile
14
- from convert_stream.mod_types.table_types import ColumnBody
12
+ from sheet_stream.type_utils import MetaDataFile
15
13
  from ocr_stream.modules import (
16
- LibOcr, DEFAULT_LIB_OCR, pytesseract, Output, pyocr,
14
+ LibOcr, DEFAULT_LIB_OCR, pytesseract, pyocr, easyocr
17
15
  )
18
16
  from ocr_stream.bin_tess import BinTesseract
19
17
 
20
- try:
21
- import pyocr.tesseract
22
- except Exception as err:
23
- print(err)
24
- pyocr = None
18
+ import cv2
19
+ from PIL import Image
20
+ from io import BytesIO
21
+ from reportlab.pdfgen import canvas
22
+ #from reportlab.lib.pagesizes import A4
23
+ from reportlab.lib.utils import ImageReader
25
24
 
26
25
 
27
26
  class TextRecognized(object):
@@ -33,6 +32,7 @@ class TextRecognized(object):
33
32
  def __init__(self, bytes_recognized: bytes):
34
33
  self.metadata: MetaDataFile = MetaDataFile()
35
34
  self.bytes_recognized: bytes = bytes_recognized
35
+ self.__text_document: str | None = None
36
36
 
37
37
  self.list_bad_char: list[str] = [
38
38
  ':', ',', ';', '$', '=',
@@ -44,8 +44,28 @@ class TextRecognized(object):
44
44
  '%', '~', '¥', '♀',
45
45
  ]
46
46
 
47
+ @property
48
+ def is_empty(self) -> bool:
49
+ txt = self.to_string()
50
+ if (txt is None) or (txt == '') or (txt == 'nas'):
51
+ return True
52
+ return False
53
+
47
54
  def to_string(self) -> str | None:
48
- return self.to_page_pdf().to_string()
55
+ if self.__text_document is None:
56
+ _pages: list[PageDocumentPdf] = self.to_document().to_pages()
57
+ content: str = ''
58
+ txt_page: str
59
+ for page in _pages:
60
+ txt_page = page.to_string()
61
+ if (txt_page is None) or (txt_page == '') or (txt_page == 'nas'):
62
+ continue
63
+ if content == '':
64
+ content = txt_page
65
+ continue
66
+ content = f'{content}\n{txt_page}'
67
+ self.__text_document = content
68
+ return self.__text_document
49
69
 
50
70
  def to_page_pdf(self) -> PageDocumentPdf:
51
71
  doc = self.to_document()
@@ -57,7 +77,7 @@ class TextRecognized(object):
57
77
  tmp_doc.metadata.dir_path = self.metadata.dir_path
58
78
  return tmp_doc
59
79
 
60
- def to_dict(self, separator: str = '\n') -> dict[str, ColumnBody]:
80
+ def to_dict(self, separator: str = '\n') -> DictTextTable:
61
81
  return self.to_page_pdf().to_dict(separator=separator)
62
82
 
63
83
  def to_dataframe(self, separator='\n') -> DataFrame:
@@ -142,6 +162,71 @@ class IPytesseract(ABCOcrTesseract):
142
162
  return TextRecognized(bt)
143
163
 
144
164
 
165
+ # ======================================================================#
166
+ # Modulo easyocr
167
+ # ======================================================================#
168
+ class IEasyOcr(ABCOcrTesseract):
169
+
170
+ def __init__(self, bin_tess: BinTesseract, *, lang: str = 'pt', tess_data_dir: str = None):
171
+ super().__init__(bin_tess, lang=lang, tess_data_dir=tess_data_dir)
172
+ self.reader: easyocr.Reader = easyocr.Reader([self.lang], gpu=True)
173
+
174
+ def to_string(self, img: Union[File, ImageObject]) -> str:
175
+ if isinstance(img, File):
176
+ img = ImageObject(img)
177
+ result = self.reader.readtext(img.to_opencv())
178
+ text = '\n'.join([res[1] for res in result])
179
+ return text
180
+
181
+ def to_reconize(self, img: Union[File, ImageObject]) -> TextRecognized:
182
+
183
+ # 1️⃣ Converter o objeto de entrada para imagem OpenCV
184
+ if isinstance(img, File):
185
+ img = ImageObject(img)
186
+ img_cv = img.to_opencv()
187
+ img_h, img_w = img_cv.shape[:2]
188
+
189
+ # 2️⃣ Reconhecer o texto com EasyOCR
190
+ results: list = self.reader.readtext(img_cv)
191
+
192
+ # 3️⃣ Converter a imagem para PDF (imagem de fundo)
193
+ buffer = BytesIO()
194
+ pdf = canvas.Canvas(buffer, pagesize=(img_w, img_h))
195
+
196
+ # Desenha a imagem original como fundo
197
+ img_pil = Image.fromarray(cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB))
198
+ pdf.drawImage(ImageReader(img_pil), 0, 0, width=img_w, height=img_h)
199
+
200
+ # 4️⃣ Adiciona o texto OCR como camada "invisível" sobre a imagem
201
+ pdf.setFont("Helvetica", 8)
202
+ pdf.setFillColorRGB(1, 1, 1, alpha=0) # texto invisível
203
+
204
+ for (bbox, text, conf) in results:
205
+ if not text.strip():
206
+ continue
207
+ # Coordenadas do bounding box (EasyOCR retorna 4 pontos)
208
+ (x1, y1), (x2, y2), (x3, y3), (x4, y4) = bbox
209
+
210
+ # Média da posição vertical
211
+ avg_y = (y1 + y2 + y3 + y4) / 4
212
+
213
+ # Posição invertida (PDF tem origem no canto inferior esquerdo)
214
+ y_pdf = img_h - avg_y
215
+
216
+ # Largura estimada
217
+ text_width = abs(x2 - x1)
218
+ pdf.drawString(x1, y_pdf, text)
219
+
220
+ pdf.showPage()
221
+ pdf.save()
222
+ buffer.seek(0)
223
+
224
+ # 5️⃣ Retorna como TextRecognized (bytes do PDF com texto embutido)
225
+ text_rec = TextRecognized(buffer.read())
226
+ text_rec.metadata = img.metadata if hasattr(img, "metadata") else MetaDataFile()
227
+ return text_rec
228
+
229
+
145
230
  # ======================================================================#
146
231
  # Modulo OCR pyocr
147
232
  # ======================================================================#
@@ -206,6 +291,10 @@ class TesseractOcr(object):
206
291
  md = IPytesseract(bin_tess, lang=lang, tess_data_dir=tess_data_dir)
207
292
  elif lib_ocr == LibOcr.PYOCR:
208
293
  md = IPyOcr(bin_tess, lang=lang, tess_data_dir=tess_data_dir)
294
+ elif lib_ocr == LibOcr.EASYOCR:
295
+ if lang is None:
296
+ lang = 'pt'
297
+ md = IEasyOcr(bin_tess, lang=lang, tess_data_dir=tess_data_dir)
209
298
  else:
210
299
  raise ValueError(f'{lib_ocr} is not supported')
211
300
  return cls(md)
@@ -1,40 +1,11 @@
1
1
  #!/usr/bin/env python3
2
2
  from __future__ import annotations
3
- from convert_stream import DocumentPdf, PageDocumentPdf
4
- from convert_stream.pdf import ConvertPdfToImages
5
- from convert_stream.image import ImageObject
3
+ import convert_stream as cs
6
4
  from ocr_stream.bin_tess import BinTesseract
7
5
  from ocr_stream.modules import LibOcr, DEFAULT_LIB_OCR
8
6
  from ocr_stream.ocr import TesseractOcr, TextRecognized
9
7
  from pandas import DataFrame
10
- import soup_files as sp
11
-
12
-
13
- class VoidPbar(sp.ABCProgressBar):
14
-
15
- def __init__(self):
16
- super().__init__()
17
-
18
- def set_percent(self, percent: float):
19
- pass
20
-
21
- def set_text(self, text: str):
22
- pass
23
-
24
-
25
- class ProgressVoid(sp.ProgressBarAdapter):
26
-
27
- def __init__(self, progress_bar: sp.ABCProgressBar = VoidPbar()):
28
- super().__init__(progress_bar)
29
-
30
- def update(self, percent: float, status: str = "-"):
31
- pass
32
-
33
- def update_percent(self, percent: float = 0):
34
- pass
35
-
36
- def update_text(self, text: str = "-"):
37
- pass
8
+ from soup_files import File, ProgressBarAdapter, CreatePbar
38
9
 
39
10
 
40
11
  class RecognizeImage(object):
@@ -59,7 +30,7 @@ class RecognizeImage(object):
59
30
  def bin_tesseract(self) -> BinTesseract:
60
31
  return self.module_ocr.mod_ocr.bin_tess
61
32
 
62
- def image_content_data(self, img: ImageObject | sp.File) -> DataFrame:
33
+ def image_content_data(self, img: cs.ImageObject | File) -> DataFrame:
63
34
  """
64
35
  Retorna uma tabela estruturada com os dados reconhecidos da imagem.
65
36
 
@@ -68,35 +39,35 @@ class RecognizeImage(object):
68
39
  nível do OCR e confiabilidade, entre outras.
69
40
 
70
41
  Parâmetros:
71
- img (ImageObject | sp.File): A imagem a ser processada, podendo ser um objeto
72
- `ImageObject` ou um arquivo `sp.File`.
42
+ img (cs.ImageObject | File): A imagem a ser processada, podendo ser um objeto
43
+ `cs.ImageObject` ou um arquivo `File`.
73
44
 
74
45
  Retorna:
75
46
  DataFrame: Uma tabela contendo os dados reconhecidos na imagem.
76
47
 
77
48
  Lança:
78
- ValueError: Se o tipo do parâmetro `img` não for `ImageObject` ou `sp.File`.
49
+ ValueError: Se o tipo do parâmetro `img` não for `cs.ImageObject` ou `File`.
79
50
 
80
- @param img: Imagem a ser processada, podendo ser uma instância de `ImageObject`
81
- ou um arquivo `sp.File`.
82
- @type img: ImageObject | sp.File
51
+ @param img: Imagem a ser processada, podendo ser uma instância de `cs.ImageObject`
52
+ ou um arquivo `File`.
53
+ @type img: cs.ImageObject | File
83
54
 
84
55
  @rtype: pandas.DataFrame
85
56
  @return: Um DataFrame com os dados reconhecidos na imagem.
86
57
 
87
- @raise ValueError: Caso o tipo de `img` não seja `ImageObject` nem `sp.File`.
58
+ @raise ValueError: Caso o tipo de `img` não seja `cs.ImageObject` nem `File`.
88
59
  """
89
60
  return self.image_recognize(img).to_dataframe()
90
61
 
91
- def image_recognize(self, img: ImageObject | sp.File, *, land_scape: bool = False) -> TextRecognized:
92
- if isinstance(img, sp.File):
93
- img = ImageObject(img)
62
+ def image_recognize(self, img: cs.ImageObject | File, *, land_scape: bool = False) -> TextRecognized:
63
+ if isinstance(img, File):
64
+ img = cs.ImageObject(img)
94
65
  if land_scape:
95
66
  img.set_landscape()
96
67
  rec: TextRecognized = self.module_ocr.to_reconize(img)
97
68
  return rec
98
69
 
99
- def image_to_string(self, img: ImageObject | sp.File) -> str:
70
+ def image_to_string(self, img: cs.ImageObject | File) -> str:
100
71
  return self.module_ocr.to_string(img)
101
72
 
102
73
 
@@ -108,50 +79,45 @@ class RecognizePdf(object):
108
79
  lib_ocr: LibOcr = DEFAULT_LIB_OCR,
109
80
  ):
110
81
  self.recognize_image: RecognizeImage = RecognizeImage(bin_tess, lib_ocr=lib_ocr)
111
- self.pbar: sp.ProgressBarAdapter = sp.CreatePbar().get()
82
+ self.pbar: ProgressBarAdapter = CreatePbar().get()
112
83
 
113
- def set_pbar(self, p: sp.ProgressBarAdapter):
84
+ def set_pbar(self, p: ProgressBarAdapter):
114
85
  self.pbar = p
115
86
 
116
- def recognize_page_pdf(self, page: PageDocumentPdf, *, dpi: int = 300) -> DocumentPdf:
87
+ def recognize_page_pdf(self, page: cs.PageDocumentPdf, *, dpi: int = 200) -> cs.DocumentPdf:
117
88
  """
118
89
  Converte a página em Imagem, reconhece o texto com OCR e
119
90
  retorna uma nova página com o texto reconhecido.
120
91
  """
121
- _doc = DocumentPdf.create_from_pages([page])
122
- _conv = ConvertPdfToImages.create(_doc)
123
- _conv.set_pbar(self.pbar)
124
- img: ImageObject = _conv.to_images(dpi=dpi)[0]
92
+ _stream = cs.PdfStream(pbar=self.pbar, dpi=dpi)
93
+ _stream.add_page(page)
94
+ img: cs.ImageObject = _stream.convert_pdf_to_images.to_images(dpi=dpi)[0]
125
95
  text_recognized: TextRecognized = self.recognize_image.image_recognize(img)
126
- del _doc
127
- del _conv
128
96
  del img
129
- text_recognized.metadata.file_path = page.metadata.file_path
130
- text_recognized.metadata.dir_path = page.metadata.dir_path
131
97
  return text_recognized.to_document()
132
98
 
133
- def recognize_document(self, doc: DocumentPdf, *, dpi: int = 300) -> DocumentPdf:
134
- _pages: list[PageDocumentPdf] = []
135
- _pages.clear()
136
- _conv = ConvertPdfToImages.create(doc)
137
- _conv.set_pbar(self.pbar)
138
- images: list[ImageObject] = _conv.to_images(dpi=dpi)
99
+ def recognize_document(self, doc: cs.DocumentPdf, *, dpi: int = 200) -> cs.DocumentPdf:
100
+ _pages: list[cs.PageDocumentPdf] = []
101
+ _stream = cs.PdfStream(pbar=self.pbar, dpi=dpi)
102
+ _stream.add_document(doc)
103
+ _conv = _stream.convert_pdf_to_images
104
+ images: list[cs.ImageObject] = _conv.to_images(dpi=dpi)
139
105
  max_num: int = len(images)
140
106
  for num, img in enumerate(images):
141
107
  self.pbar.update(
142
108
  ((num + 1) / max_num) * 100,
143
- f'OCR Documento [{num+1} de {max_num}]'
109
+ f'OCR Documento: [{num+1} de {max_num}]'
144
110
  )
145
111
  text_recognized = self.recognize_image.image_recognize(img)
146
112
  _pages.append(text_recognized.to_page_pdf())
147
113
  print()
148
114
  self.pbar.stop()
149
- new_doc = DocumentPdf.create_from_pages(_pages)
115
+ new_doc = cs.DocumentPdf.create_from_pages(_pages)
150
116
  new_doc.metadata = doc.metadata
151
117
  return new_doc
152
118
 
153
- def recognize_file_pdf(self, file: sp.File, *, dpi: int = 300) -> DocumentPdf:
154
- file_doc = DocumentPdf.create_from_file(file)
119
+ def recognize_file_pdf(self, file: File, *, dpi: int = 300) -> cs.DocumentPdf:
120
+ file_doc = cs.DocumentPdf.create_from_file(file)
155
121
  recognized_doc = self.recognize_document(file_doc, dpi=dpi)
156
122
  del file_doc
157
123
  return recognized_doc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ocr_stream
3
- Version: 2.4.1
3
+ Version: 2.5
4
4
  Summary: Extrair textos de documentos digitalizados e imagens.
5
5
  Author: Bruno Chaves
6
6
  Requires-Python: >=3.11
@@ -12,8 +12,8 @@ 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.4.1
16
- Requires-Dist: soup_files>=1.4
15
+ Requires-Dist: convert_stream>=2.5
16
+ Requires-Dist: soup_files>=1.4.2
17
17
 
18
18
  # ocrlib
19
19
 
@@ -5,5 +5,5 @@ pandas
5
5
  requests>=2.32.4
6
6
  opencv-python
7
7
  pytesseract
8
- convert_stream>=2.4.1
9
- soup_files>=1.4
8
+ convert_stream>=2.5
9
+ soup_files>=1.4.2
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ocr_stream"
7
- version = "2.4.1"
7
+ version = "2.5"
8
8
  authors = [
9
9
  { name="Bruno Chaves"},
10
10
  ]
@@ -21,8 +21,8 @@ dependencies = [
21
21
  "requests>=2.32.4",
22
22
  "opencv-python",
23
23
  "pytesseract",
24
- "convert_stream>=2.4.1",
25
- "soup_files>=1.4",
24
+ "convert_stream>=2.5",
25
+ "soup_files>=1.4.2",
26
26
  ]
27
27
 
28
28
  [tool.setuptools]
File without changes
File without changes