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.

@@ -1,32 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ocr_stream
3
- Version: 1.2
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==3.0.1
21
- Requires-Dist: PyMuPDF==1.25.5
22
- Requires-Dist: reportlab==4.3.1
23
- Requires-Dist: openpyxl==3.1.5
24
- Requires-Dist: pandas==2.2.3
25
- Requires-Dist: Pillow==11.2.1
26
- Requires-Dist: opencv-python==4.11.0.86
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,5 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+
4
+ __version__ = '1.3'
5
+ __modify_data__ = '2025-07-06'
@@ -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)
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env python3
2
2
  from .m_modules_ocr import LibraryOCR, ABCTextRecognized, ABCModuleOcr
3
- from .m_extractors import ABCRecognizeImage
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env python3
2
+
@@ -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
- def __init__(self, *, cmd_executable:File, lang:str=None, tess_data_dir:Directory=None):
48
- self.cmd_executable:File = cmd_executable
49
- self.lang:str = lang
50
- self.tess_data_dir:Directory = tess_data_dir
51
- self.current_library_ocr:LibraryOCR = None
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
- from ocr_stream.models import (
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
- def __init__(self, value:str=None, *, separator:str='\n', column_text='TEXT', file:File):
42
- # Todas as linhas que foram reconhecidas em uma imagem/página PDF.
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', '').value.strip()
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 = LibraryPDF.FITZ
231
+ self.bytes_recognized,
232
+ library=LibraryPDF.FITZ
239
233
  )
240
234
  return _page
241
-
235
+
242
236
  def to_document(self) -> DocumentPdf:
243
- doc = DocumentPdf(pages=self.to_page_pdf())
244
- return doc
245
-
246
- def to_dict(self, separator = '\n', column_text = 'TEXT') -> Dict[str, List[str]]:
247
- image_dict:Dict[str, List[str]] = {
248
- column_text: [],
249
- 'NUM_LINHA': [],
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
- column_text: ['nan'],
255
- 'NUM_LINHA': ['nan'],
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['NUM_LINHA'].append(num+1)
262
- return image_dict
263
-
264
- def to_dataframe(self, separator = '\n', column_text = 'TEXT') -> DataFrame:
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
- class IModulePytesseract(ABCModuleOcr):
273
- def __init__(self, *, cmd_executable, lang = None, tess_data_dir = None):
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
- img.to_image_pil(),
306
- lang=self.lang,
307
- config=self.__get_tess_dir_config()
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
- img.to_image_pil(),
321
- lang=self.lang,
322
- config=self.__get_tess_dir_config()
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
- class IModulePyOcr(ABCModuleOcr):
349
- def __init__(self, *, cmd_executable, lang = None, tess_data_dir = None):
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 (e)
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(ABCModuleOcr):
389
- def __init__(self, module_ocr: ABCModuleOcr):
390
- super().__init__(
391
- cmd_executable=module_ocr.cmd_executable,
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
- cls,
409
- library_ocr = LibraryOCR.PYTESSERACT,
410
- *,
411
- path_tesseract: File,
412
- lang = None,
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 = IModulePytesseract(cmd_executable=path_tesseract, lang=lang, tess_data_dir=tess_data_dir)
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 = IModulePyOcr(cmd_executable=path_tesseract, lang=lang, tess_data_dir=tess_data_dir)
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.2
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==3.0.1
21
- Requires-Dist: PyMuPDF==1.25.5
22
- Requires-Dist: reportlab==4.3.1
23
- Requires-Dist: openpyxl==3.1.5
24
- Requires-Dist: pandas==2.2.3
25
- Requires-Dist: Pillow==11.2.1
26
- Requires-Dist: opencv-python==4.11.0.86
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
@@ -0,0 +1,9 @@
1
+ PyPDF2
2
+ PyMuPDF
3
+ reportlab
4
+ openpyxl
5
+ pandas
6
+ Pillow>=11.3.0
7
+ opencv-python
8
+ convert_stream
9
+ soup_files
@@ -4,22 +4,23 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ocr_stream"
7
- version = "1.2"
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==3.0.1",
17
- "PyMuPDF==1.25.5",
18
- "reportlab==4.3.1",
19
- "openpyxl==3.1.5",
20
- "pandas==2.2.3",
21
- "Pillow==11.2.1",
22
- "opencv-python==4.11.0.86",
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,5 +0,0 @@
1
- #!/usr/bin/env python3
2
- #
3
-
4
- __version__ = '1.2'
5
- __modify_data__ = '2025-06-22'
@@ -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,9 +0,0 @@
1
- PyPDF2==3.0.1
2
- PyMuPDF==1.25.5
3
- reportlab==4.3.1
4
- openpyxl==3.1.5
5
- pandas==2.2.3
6
- Pillow==11.2.1
7
- opencv-python==4.11.0.86
8
- convert_stream
9
- soup_files
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