convert-stream 2.5__tar.gz → 2.5.1__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.
- {convert_stream-2.5 → convert_stream-2.5.1}/PKG-INFO +1 -1
- convert_stream-2.5.1/convert_stream/convert/__init__.py +6 -0
- convert_stream-2.5.1/convert_stream/convert/image_to_pdf.py +349 -0
- convert_stream-2.5.1/convert_stream/convert/pdf_to_image.py +223 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream.egg-info/PKG-INFO +1 -1
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream.egg-info/SOURCES.txt +3 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/pyproject.toml +2 -1
- {convert_stream-2.5 → convert_stream-2.5.1}/README.md +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/__init__.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/__main__.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/_version.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/doc_stream.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/image/__init__.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/image/img_object.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/mod_types/__init__.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/mod_types/enums.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/mod_types/modules.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/pdf/__init__.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/pdf/pdf_document.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/pdf/pdf_page.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/table_files.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/text/__init__.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/text/find_text.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream/text/terminal.py +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream.egg-info/dependency_links.txt +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream.egg-info/requires.txt +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/convert_stream.egg-info/top_level.txt +0 -0
- {convert_stream-2.5 → convert_stream-2.5.1}/setup.cfg +0 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Módulo para trabalhar com imagens
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
from io import BytesIO
|
|
9
|
+
from soup_files import File, Directory, ProgressBarAdapter
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from convert_stream.mod_types.enums import LibImageToPdf
|
|
12
|
+
from convert_stream.mod_types.modules import (
|
|
13
|
+
MOD_CANVAS, DEFAULT_LIB_IMAGE_TO_PDF, canvas, letter, ImageReader
|
|
14
|
+
)
|
|
15
|
+
from convert_stream.pdf import DocumentPdf
|
|
16
|
+
from convert_stream.pdf.pdf_page import fitz
|
|
17
|
+
from convert_stream.image.img_object import MOD_IMG_PIL, Image, ImageObject, CollectionImages
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ABCConvertImageToPdf(ABC):
|
|
21
|
+
|
|
22
|
+
def __init__(self, collection_images: CollectionImages):
|
|
23
|
+
self.collection_images: CollectionImages = collection_images
|
|
24
|
+
self.pbar: ProgressBarAdapter = ProgressBarAdapter()
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def set_pbar(self, p: ProgressBarAdapter):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def to_document(self, land_scape: bool = True, a4: bool = False) -> DocumentPdf:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def to_file_pdf(self, output_file: File, *, land_scape: bool = True, a4: bool = False) -> None:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ImplementImageToPdfCanvas(ABCConvertImageToPdf):
|
|
40
|
+
|
|
41
|
+
def __init__(self, collection_images: CollectionImages):
|
|
42
|
+
super().__init__(collection_images)
|
|
43
|
+
|
|
44
|
+
def set_pbar(self, p: ProgressBarAdapter):
|
|
45
|
+
self.pbar = p
|
|
46
|
+
self.collection_images.set_pbar(p)
|
|
47
|
+
|
|
48
|
+
def to_document(self, land_scape: bool = True, a4: bool = False) -> DocumentPdf:
|
|
49
|
+
if not MOD_CANVAS:
|
|
50
|
+
raise RuntimeError("A biblioteca 'reportlab' não está disponível.")
|
|
51
|
+
|
|
52
|
+
if self.collection_images.is_empty:
|
|
53
|
+
raise ValueError("A lista de imagens não pode estar vazia.")
|
|
54
|
+
|
|
55
|
+
buffer = BytesIO()
|
|
56
|
+
max_num: int = self.collection_images.length
|
|
57
|
+
self.pbar.start()
|
|
58
|
+
if land_scape:
|
|
59
|
+
self.collection_images.set_land_scape()
|
|
60
|
+
|
|
61
|
+
# Lógica para determinar o tamanho inicial da página
|
|
62
|
+
first_img_obj = self.collection_images[0]
|
|
63
|
+
first_img_width, first_img_height = first_img_obj.get_dimensions()
|
|
64
|
+
|
|
65
|
+
if a4:
|
|
66
|
+
# Se for A4, o tamanho da página é fixo desde o início
|
|
67
|
+
c = canvas.Canvas(buffer, pagesize=letter)
|
|
68
|
+
else:
|
|
69
|
+
# Se não for A4, o canvas é inicializado com as dimensões da primeira imagem
|
|
70
|
+
c = canvas.Canvas(buffer, pagesize=(first_img_width, first_img_height))
|
|
71
|
+
|
|
72
|
+
# Processa a primeira imagem
|
|
73
|
+
self.pbar.update(
|
|
74
|
+
(1 / max_num) * 100,
|
|
75
|
+
f'Adicionando imagem ao Documento [1 de {max_num}]'
|
|
76
|
+
)
|
|
77
|
+
img_bytes: BytesIO = first_img_obj.to_bytes()
|
|
78
|
+
img_bytes.seek(0)
|
|
79
|
+
img_reader = ImageReader(img_bytes)
|
|
80
|
+
|
|
81
|
+
if a4:
|
|
82
|
+
# Lógica de redimensionamento e centralização para A4
|
|
83
|
+
page_width, page_height = letter
|
|
84
|
+
scale_factor = min(page_width / first_img_width, page_height / first_img_height)
|
|
85
|
+
scaled_width = first_img_width * scale_factor
|
|
86
|
+
scaled_height = first_img_height * scale_factor
|
|
87
|
+
x_pos = (page_width - scaled_width) / 2
|
|
88
|
+
y_pos = (page_height - scaled_height) / 2
|
|
89
|
+
c.drawImage(img_reader, x_pos, y_pos, width=scaled_width, height=scaled_height)
|
|
90
|
+
else:
|
|
91
|
+
# Desenha a imagem preenchendo a página que já tem o tamanho correto
|
|
92
|
+
c.drawImage(img_reader, 0, 0, width=first_img_width, height=first_img_height)
|
|
93
|
+
|
|
94
|
+
# Processa as imagens restantes
|
|
95
|
+
for num, img_obj in enumerate(self.collection_images[1:], 1):
|
|
96
|
+
|
|
97
|
+
self.pbar.update(
|
|
98
|
+
((num + 1) / max_num) * 100,
|
|
99
|
+
f'Adicionando imagem ao Documento [{num + 1} de {max_num}]'
|
|
100
|
+
)
|
|
101
|
+
img_bytes = img_obj.to_bytes()
|
|
102
|
+
img_bytes.seek(0)
|
|
103
|
+
img_reader = ImageReader(img_bytes)
|
|
104
|
+
img_width, img_height = img_obj.get_dimensions()
|
|
105
|
+
# Cria nova página
|
|
106
|
+
c.showPage()
|
|
107
|
+
|
|
108
|
+
if a4:
|
|
109
|
+
# O tamanho da página é fixo, apenas desenha a imagem centralizada e redimensionada
|
|
110
|
+
page_width, page_height = letter
|
|
111
|
+
scale_factor = min(page_width / img_width, page_height / img_height)
|
|
112
|
+
scaled_width = img_width * scale_factor
|
|
113
|
+
scaled_height = img_height * scale_factor
|
|
114
|
+
x_pos = (page_width - scaled_width) / 2
|
|
115
|
+
y_pos = (page_height - scaled_height) / 2
|
|
116
|
+
c.drawImage(img_reader, x_pos, y_pos, width=scaled_width, height=scaled_height)
|
|
117
|
+
else:
|
|
118
|
+
# Ajusta o tamanho da nova página para as dimensões da imagem atual
|
|
119
|
+
c.setPageSize((img_width, img_height))
|
|
120
|
+
c.drawImage(img_reader, 0, 0, width=img_width, height=img_height)
|
|
121
|
+
|
|
122
|
+
c.save()
|
|
123
|
+
buffer.seek(0)
|
|
124
|
+
self.pbar.stop()
|
|
125
|
+
return DocumentPdf.create_from_bytes(buffer)
|
|
126
|
+
|
|
127
|
+
def to_file_pdf(self, output_file: File, *, land_scape: bool = True, a4: bool = False) -> None:
|
|
128
|
+
self.to_document(land_scape=land_scape, a4=a4).to_file(output_file)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class ImplementImageToPdfPil(ABCConvertImageToPdf):
|
|
132
|
+
"""
|
|
133
|
+
Classe para converter uma lista de ImageObject em um DocumentPdf
|
|
134
|
+
usando a biblioteca Pillow (PIL).
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
def __init__(self, collection_images: CollectionImages):
|
|
138
|
+
super().__init__(collection_images)
|
|
139
|
+
|
|
140
|
+
def set_pbar(self, p: ProgressBarAdapter):
|
|
141
|
+
self.pbar = p
|
|
142
|
+
self.collection_images.set_pbar(p)
|
|
143
|
+
|
|
144
|
+
def to_document(self, land_scape: bool = True, a4: bool = False) -> DocumentPdf:
|
|
145
|
+
if not MOD_IMG_PIL:
|
|
146
|
+
raise RuntimeError("A biblioteca 'Pillow' não está disponível.")
|
|
147
|
+
|
|
148
|
+
if self.collection_images.length == 0:
|
|
149
|
+
raise ValueError("A lista de imagens não pode estar vazia.")
|
|
150
|
+
|
|
151
|
+
if land_scape:
|
|
152
|
+
self.collection_images.set_land_scape()
|
|
153
|
+
|
|
154
|
+
pil_images_to_save = []
|
|
155
|
+
if a4:
|
|
156
|
+
# Obtém as dimensões da página A4 em píxels
|
|
157
|
+
# Usando uma resolução de 100 DPI para consistência
|
|
158
|
+
page_width, page_height = letter # Padrão do reportlab
|
|
159
|
+
page_size = (int(page_width), int(page_height))
|
|
160
|
+
|
|
161
|
+
self.pbar.start()
|
|
162
|
+
max_num = self.collection_images.length
|
|
163
|
+
for num, img_obj in enumerate(self.collection_images):
|
|
164
|
+
self.pbar.update(
|
|
165
|
+
((num + 1) / max_num) * 100,
|
|
166
|
+
f'Redimensionando e ajustando imagem para A4 [{num + 1} de {max_num}]'
|
|
167
|
+
)
|
|
168
|
+
original_pil_image = img_obj.to_pil()
|
|
169
|
+
img_width, img_height = original_pil_image.size
|
|
170
|
+
|
|
171
|
+
# Calcula o fator de escala para ajustar a imagem à página, mantendo a proporção
|
|
172
|
+
scale_factor = min(page_size[0] / img_width, page_size[1] / img_height)
|
|
173
|
+
scaled_width = int(img_width * scale_factor)
|
|
174
|
+
scaled_height = int(img_height * scale_factor)
|
|
175
|
+
|
|
176
|
+
# Redimensiona a imagem
|
|
177
|
+
resized_image = original_pil_image.resize(
|
|
178
|
+
(scaled_width, scaled_height), Image.Resampling.LANCZOS
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Criar imagem de fundo branca com o tamanho A4
|
|
182
|
+
new_image = Image.new('RGB', page_size, 'white')
|
|
183
|
+
|
|
184
|
+
# Centraliza a imagem redimensionada na nova imagem
|
|
185
|
+
x_pos = (page_size[0] - scaled_width) // 2
|
|
186
|
+
y_pos = (page_size[1] - scaled_height) // 2
|
|
187
|
+
new_image.paste(resized_image, (x_pos, y_pos))
|
|
188
|
+
|
|
189
|
+
pil_images_to_save.append(new_image)
|
|
190
|
+
self.pbar.stop()
|
|
191
|
+
else:
|
|
192
|
+
# Para a4 = False, não precisa redimensionar. Pillow ajusta o tamanho da página.
|
|
193
|
+
pil_images_to_save = [img.to_pil() for img in self.collection_images]
|
|
194
|
+
|
|
195
|
+
buffer = BytesIO()
|
|
196
|
+
try:
|
|
197
|
+
first_image_pil = pil_images_to_save[0]
|
|
198
|
+
other_images_pil = pil_images_to_save[1:]
|
|
199
|
+
|
|
200
|
+
first_image_pil.save(
|
|
201
|
+
buffer,
|
|
202
|
+
'PDF',
|
|
203
|
+
resolution=140.0,
|
|
204
|
+
save_all=True,
|
|
205
|
+
append_images=other_images_pil
|
|
206
|
+
)
|
|
207
|
+
except Exception as e:
|
|
208
|
+
raise RuntimeError(f"Erro ao criar o PDF com Pillow: {e}") from e
|
|
209
|
+
|
|
210
|
+
buffer.seek(0)
|
|
211
|
+
return DocumentPdf.create_from_bytes(buffer)
|
|
212
|
+
|
|
213
|
+
def to_file_pdf(self, output_file: File, *, land_scape: bool = True, a4: bool = False) -> None:
|
|
214
|
+
self.to_document(land_scape=land_scape, a4=a4).to_file(output_file)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class ImplementImageToPdfFitz(ABCConvertImageToPdf):
|
|
218
|
+
"""
|
|
219
|
+
Classe para converter uma lista de ImageObject em um DocumentPdf
|
|
220
|
+
usando a biblioteca PyMuPDF (fitz).
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
def __init__(self, collection_images: CollectionImages):
|
|
224
|
+
super().__init__(collection_images)
|
|
225
|
+
|
|
226
|
+
def set_pbar(self, p: ProgressBarAdapter):
|
|
227
|
+
self.pbar = p
|
|
228
|
+
self.collection_images.set_pbar(p)
|
|
229
|
+
|
|
230
|
+
def to_document(self, land_scape: bool = True, a4: bool = False) -> DocumentPdf:
|
|
231
|
+
max_num: int = self.collection_images.length
|
|
232
|
+
if max_num == 0:
|
|
233
|
+
raise ValueError('Adicione imagens para prosseguir')
|
|
234
|
+
self.pbar.start()
|
|
235
|
+
self.pbar.update(0, f'Convertendo {max_num} imagens em Documento PDF')
|
|
236
|
+
buffer = BytesIO()
|
|
237
|
+
doc = fitz.open() # Cria um novo documento PDF vazio
|
|
238
|
+
|
|
239
|
+
for num, img_obj in enumerate(self.collection_images):
|
|
240
|
+
self.pbar.update(
|
|
241
|
+
((num + 1) / max_num) * 100,
|
|
242
|
+
f'Convertendo: [{num + 1} de {max_num}]'
|
|
243
|
+
)
|
|
244
|
+
if land_scape:
|
|
245
|
+
img_obj.set_landscape()
|
|
246
|
+
|
|
247
|
+
# Converte a imagem para bytes
|
|
248
|
+
img_bytes_obj = img_obj.to_bytes()
|
|
249
|
+
# Obtém as dimensões da imagem e da página
|
|
250
|
+
img_width, img_height = img_obj.get_dimensions()
|
|
251
|
+
|
|
252
|
+
# Adiciona uma nova página ao documento
|
|
253
|
+
if a4:
|
|
254
|
+
page = doc.new_page()
|
|
255
|
+
else:
|
|
256
|
+
page = doc.new_page(width=img_width, height=img_height)
|
|
257
|
+
|
|
258
|
+
# Cria um retângulo que preenche a página
|
|
259
|
+
rect = page.rect
|
|
260
|
+
page_width, page_height = rect.width, rect.height
|
|
261
|
+
|
|
262
|
+
# Calcula o fator de escala para ajustar a imagem à página
|
|
263
|
+
scale_factor_w = page_width / img_width
|
|
264
|
+
scale_factor_h = page_height / img_height
|
|
265
|
+
scale_factor = min(scale_factor_w, scale_factor_h)
|
|
266
|
+
|
|
267
|
+
# Ajusta o retângulo de inserção para centralizar a imagem
|
|
268
|
+
scaled_width = img_width * scale_factor
|
|
269
|
+
scaled_height = img_height * scale_factor
|
|
270
|
+
x0 = (page_width - scaled_width) / 2
|
|
271
|
+
y0 = (page_height - scaled_height) / 2
|
|
272
|
+
|
|
273
|
+
# Insere a imagem no retângulo calculado
|
|
274
|
+
page.insert_image(
|
|
275
|
+
fitz.Rect(x0, y0, x0 + scaled_width, y0 + scaled_height),
|
|
276
|
+
stream=img_bytes_obj
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# Salva o documento no buffer de memória
|
|
280
|
+
doc.save(buffer)
|
|
281
|
+
doc.close()
|
|
282
|
+
buffer.seek(0)
|
|
283
|
+
self.pbar.update(100, 'Conversão concluída')
|
|
284
|
+
print()
|
|
285
|
+
self.pbar.stop()
|
|
286
|
+
return DocumentPdf.create_from_bytes(buffer)
|
|
287
|
+
|
|
288
|
+
def to_file_pdf(self, output_file: File, *, land_scape: bool = True, a4: bool = False) -> None:
|
|
289
|
+
self.to_document(land_scape=land_scape).to_file(output_file)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class ConvertImageToPdf(object):
|
|
293
|
+
"""
|
|
294
|
+
Classe com padrão ADAPTER para converter Imagens em documento(s) PDF.
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
def __init__(
|
|
298
|
+
self,
|
|
299
|
+
collection_images: CollectionImages, *,
|
|
300
|
+
lib_img_to_pdf: LibImageToPdf = LibImageToPdf.IMAGE_TO_PDF_FITZ
|
|
301
|
+
):
|
|
302
|
+
if lib_img_to_pdf == LibImageToPdf.IMAGE_TO_PDF_CANVAS:
|
|
303
|
+
self.convert: ABCConvertImageToPdf = ImplementImageToPdfCanvas(collection_images)
|
|
304
|
+
elif lib_img_to_pdf == LibImageToPdf.IMAGE_TO_PDF_PIL:
|
|
305
|
+
self.convert: ABCConvertImageToPdf = ImplementImageToPdfPil(collection_images)
|
|
306
|
+
elif lib_img_to_pdf == LibImageToPdf.IMAGE_TO_PDF_FITZ:
|
|
307
|
+
self.convert: ABCConvertImageToPdf = ImplementImageToPdfFitz(collection_images)
|
|
308
|
+
else:
|
|
309
|
+
raise NotImplementedError()
|
|
310
|
+
|
|
311
|
+
self._count: int = 0
|
|
312
|
+
|
|
313
|
+
@property
|
|
314
|
+
def is_null(self) -> bool:
|
|
315
|
+
return self.convert.collection_images.is_empty
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def pbar(self) -> ProgressBarAdapter:
|
|
319
|
+
return self.convert.pbar
|
|
320
|
+
|
|
321
|
+
def set_pbar(self, p: ProgressBarAdapter):
|
|
322
|
+
self.convert.set_pbar(p)
|
|
323
|
+
|
|
324
|
+
def add_file(self, file: File) -> None:
|
|
325
|
+
self.convert.collection_images.add_file_image(file)
|
|
326
|
+
|
|
327
|
+
def add_files(self, files: list[File]) -> None:
|
|
328
|
+
self.convert.collection_images.add_files_image(files)
|
|
329
|
+
|
|
330
|
+
def add_image(self, image: ImageObject) -> None:
|
|
331
|
+
self.convert.collection_images.add_image(image)
|
|
332
|
+
|
|
333
|
+
def add_images(self, images: list[ImageObject]) -> None:
|
|
334
|
+
self.convert.collection_images.add_images(images)
|
|
335
|
+
|
|
336
|
+
def add_directory(self, src_dir: Directory, max_files: int = 4000) -> None:
|
|
337
|
+
self.convert.collection_images.add_directory_images(src_dir, max_files=max_files)
|
|
338
|
+
|
|
339
|
+
def to_document(self, land_scape: bool = True, *, a4: bool = False) -> DocumentPdf:
|
|
340
|
+
return self.convert.to_document(land_scape, a4=a4)
|
|
341
|
+
|
|
342
|
+
def to_file_pdf(self, output_file: File, *, land_scape: bool = True, a4: bool = False) -> None:
|
|
343
|
+
self.convert.to_file_pdf(output_file, land_scape=land_scape, a4=a4)
|
|
344
|
+
|
|
345
|
+
def set_gausian_blur(self, sigma: float = 0.8) -> None:
|
|
346
|
+
self.convert.collection_images.set_gausian_blur(sigma)
|
|
347
|
+
|
|
348
|
+
def set_land_scape(self):
|
|
349
|
+
self.convert.collection_images.set_land_scape()
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
"""
|
|
4
|
+
Módulo para trabalhar com imagens
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
|
|
9
|
+
from sheet_stream.type_utils import MetaDataFile
|
|
10
|
+
|
|
11
|
+
from convert_stream import CollectionImages
|
|
12
|
+
from soup_files import Directory, ProgressBarAdapter, CreatePbar
|
|
13
|
+
from convert_stream.mod_types.enums import LibPdfToImage
|
|
14
|
+
from convert_stream.mod_types.modules import DEFAULT_LIB_PDF_TO_IMG, DEFAULT_LIB_IMAGE, LibPDF
|
|
15
|
+
from convert_stream.image.img_object import ImageObject, LibImage
|
|
16
|
+
from convert_stream.pdf.pdf_document import DocumentPdf
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
import fitz
|
|
21
|
+
MOD_FITZ = True
|
|
22
|
+
except ImportError:
|
|
23
|
+
try:
|
|
24
|
+
import pymupdf as fitz
|
|
25
|
+
from pymupdf import Page, Pixmap
|
|
26
|
+
MOD_FITZ = True
|
|
27
|
+
except ImportError:
|
|
28
|
+
fitz = object
|
|
29
|
+
fitz.Page = object
|
|
30
|
+
fitz.TextPage = object
|
|
31
|
+
Page = object
|
|
32
|
+
Pixmap = object
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ABCConvertPdf(ABC):
|
|
36
|
+
|
|
37
|
+
def __init__(self, document: DocumentPdf):
|
|
38
|
+
self.document: DocumentPdf = document
|
|
39
|
+
self.lib_pdf_to_image: LibPdfToImage = DEFAULT_LIB_PDF_TO_IMG
|
|
40
|
+
self.pbar: ProgressBarAdapter = CreatePbar().get()
|
|
41
|
+
|
|
42
|
+
def set_pbar(self, pbar: ProgressBarAdapter):
|
|
43
|
+
self.pbar = pbar
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def to_images(
|
|
47
|
+
self, *,
|
|
48
|
+
dpi: int = 150,
|
|
49
|
+
lib_image: LibImage = DEFAULT_LIB_IMAGE,
|
|
50
|
+
) -> list[ImageObject]:
|
|
51
|
+
"""
|
|
52
|
+
Converte as páginas PDF do documento em lista de objetos imagem ImageObject
|
|
53
|
+
|
|
54
|
+
:param dpi: DPI do documento, resolução da renderização.
|
|
55
|
+
:param lib_image: Biblioteca para manipular imagens PIL/OpenCv
|
|
56
|
+
"""
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def to_files_image(
|
|
61
|
+
self,
|
|
62
|
+
output_dir: Directory, *,
|
|
63
|
+
replace: bool = False,
|
|
64
|
+
gaussian_filter: bool = False,
|
|
65
|
+
dpi: int = 300,
|
|
66
|
+
lib_image: LibImage = DEFAULT_LIB_IMAGE,
|
|
67
|
+
) -> None:
|
|
68
|
+
"""
|
|
69
|
+
Converte todas as páginas do documento em objeto de imagem e salva no disco
|
|
70
|
+
em formato de imagem PNG.
|
|
71
|
+
"""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ImplementConvertPdfFitz(ABCConvertPdf):
|
|
76
|
+
|
|
77
|
+
def __init__(self, document: DocumentPdf):
|
|
78
|
+
super().__init__(document)
|
|
79
|
+
self.lib_pdf_to_image: LibPdfToImage = LibPdfToImage.PDF_TO_IMG_FITZ
|
|
80
|
+
|
|
81
|
+
def __get_pages(self) -> list[Page]:
|
|
82
|
+
pages = self.document.to_pages()
|
|
83
|
+
fitz_pages = []
|
|
84
|
+
for p in pages:
|
|
85
|
+
fitz_pages.append(p.implement_page_pdf.mod_page)
|
|
86
|
+
return fitz_pages
|
|
87
|
+
|
|
88
|
+
def to_images(
|
|
89
|
+
self, *,
|
|
90
|
+
dpi: int = 200,
|
|
91
|
+
lib_image: LibImage = LibImage.PIL
|
|
92
|
+
) -> list[ImageObject]:
|
|
93
|
+
"""
|
|
94
|
+
Converte um Documento em lista de objetos ImageObject.
|
|
95
|
+
"""
|
|
96
|
+
images: list[ImageObject] = []
|
|
97
|
+
_metadata: MetaDataFile = self.document.metadata
|
|
98
|
+
|
|
99
|
+
pages_fitz: list[Page] = self.__get_pages()
|
|
100
|
+
_count = len(pages_fitz)
|
|
101
|
+
for n, pg in enumerate(pages_fitz):
|
|
102
|
+
self.pbar.update(
|
|
103
|
+
((n+1)/_count) * 100,
|
|
104
|
+
f'[Documento para Imagens]: página {n+1}/{_count}'
|
|
105
|
+
)
|
|
106
|
+
pix: Pixmap = pg.get_pixmap(dpi=dpi)
|
|
107
|
+
img = ImageObject.create_from_bytes(
|
|
108
|
+
pix.tobytes('png', jpg_quality=100),
|
|
109
|
+
lib_image=LibImage.PIL,
|
|
110
|
+
)
|
|
111
|
+
img.metadata.name = _metadata.name
|
|
112
|
+
img.metadata.file_path = _metadata.file_path
|
|
113
|
+
images.append(img)
|
|
114
|
+
return images
|
|
115
|
+
|
|
116
|
+
def to_files_image(
|
|
117
|
+
self,
|
|
118
|
+
output_dir: Directory, *,
|
|
119
|
+
replace: bool = False,
|
|
120
|
+
gaussian_filter: bool = False,
|
|
121
|
+
dpi: int = 300,
|
|
122
|
+
lib_image: LibImage = LibImage.PIL
|
|
123
|
+
) -> None:
|
|
124
|
+
pages_fitz: list[Page] = self.__get_pages()
|
|
125
|
+
_count = len(pages_fitz)
|
|
126
|
+
for n, pg in enumerate(pages_fitz):
|
|
127
|
+
self.pbar.update(
|
|
128
|
+
((n + 1) / _count) * 100,
|
|
129
|
+
f'[Documento para arquivos de imagens]: {n + 1}/{_count}'
|
|
130
|
+
)
|
|
131
|
+
out_file = output_dir.join_file(f'pag-{n+1}.png')
|
|
132
|
+
if not replace:
|
|
133
|
+
if out_file.exists():
|
|
134
|
+
self.pbar.update_text(f'Pulando: {out_file.basename()}')
|
|
135
|
+
continue
|
|
136
|
+
pix: Pixmap = pg.get_pixmap(dpi=dpi)
|
|
137
|
+
img = ImageObject.create_from_bytes(
|
|
138
|
+
pix.tobytes('png', jpg_quality=100),
|
|
139
|
+
lib_image=LibImage.PIL,
|
|
140
|
+
)
|
|
141
|
+
img.to_file(out_file)
|
|
142
|
+
print()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class ConvertPdfToImages(object):
|
|
146
|
+
|
|
147
|
+
def __init__(self, mod_conv_to_img: ABCConvertPdf | DocumentPdf):
|
|
148
|
+
if isinstance(mod_conv_to_img, ABCConvertPdf):
|
|
149
|
+
self.mod_convert_to_image: ABCConvertPdf = mod_conv_to_img
|
|
150
|
+
elif isinstance(mod_conv_to_img, ImplementConvertPdfFitz):
|
|
151
|
+
self.mod_convert_to_image: ABCConvertPdf = mod_conv_to_img
|
|
152
|
+
elif isinstance(mod_conv_to_img, DocumentPdf):
|
|
153
|
+
self.mod_convert_to_image = ImplementConvertPdfFitz(mod_conv_to_img)
|
|
154
|
+
else:
|
|
155
|
+
raise NotImplementedError()
|
|
156
|
+
|
|
157
|
+
def set_pbar(self, pbar: ProgressBarAdapter):
|
|
158
|
+
self.mod_convert_to_image.set_pbar(pbar)
|
|
159
|
+
|
|
160
|
+
def to_images(
|
|
161
|
+
self, *,
|
|
162
|
+
dpi: int = 300,
|
|
163
|
+
lib_image: LibImage = LibImage.PIL,
|
|
164
|
+
) -> list[ImageObject]:
|
|
165
|
+
return self.mod_convert_to_image.to_images(dpi=dpi, lib_image=lib_image)
|
|
166
|
+
|
|
167
|
+
def to_files_image(
|
|
168
|
+
self,
|
|
169
|
+
output_dir: Directory, *,
|
|
170
|
+
replace: bool = False,
|
|
171
|
+
gaussian_filter: bool = False,
|
|
172
|
+
dpi: int = 300,
|
|
173
|
+
lib_image: LibImage = LibImage.PIL,
|
|
174
|
+
) -> None:
|
|
175
|
+
self.mod_convert_to_image.to_files_image(
|
|
176
|
+
dpi=dpi,
|
|
177
|
+
lib_image=lib_image,
|
|
178
|
+
replace=replace,
|
|
179
|
+
output_dir=output_dir,
|
|
180
|
+
gaussian_filter=gaussian_filter
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
def inner_images(self) -> CollectionImages:
|
|
184
|
+
"""
|
|
185
|
+
Extrair imagens embutidas nas páginas PDF.
|
|
186
|
+
"""
|
|
187
|
+
# doc = Document(stream=page_bytes, filetype="pdf")
|
|
188
|
+
collection_imgs: CollectionImages = CollectionImages([])
|
|
189
|
+
tmp_doc: fitz.Document
|
|
190
|
+
if self.mod_convert_to_image.document.lib_pdf == LibPDF.FITZ:
|
|
191
|
+
tmp_doc: fitz.Document = self.mod_convert_to_image.document.get_real_document()
|
|
192
|
+
elif self.mod_convert_to_image.document.lib_pdf == LibPDF.PYPDF:
|
|
193
|
+
tmp_doc = fitz.Document(
|
|
194
|
+
stream=self.mod_convert_to_image.document.to_bytes().getvalue(), filetype="pdf"
|
|
195
|
+
)
|
|
196
|
+
else:
|
|
197
|
+
raise NotImplementedError()
|
|
198
|
+
|
|
199
|
+
page: fitz.Page
|
|
200
|
+
for num, page in enumerate(tmp_doc):
|
|
201
|
+
# Extrair imagens embutidas na página
|
|
202
|
+
images_list: list = page.get_images(full=True)
|
|
203
|
+
for img in images_list:
|
|
204
|
+
try:
|
|
205
|
+
# Referência do objeto da imagem
|
|
206
|
+
xref = img[0]
|
|
207
|
+
# Extrair imagem
|
|
208
|
+
base_image = tmp_doc.extract_image(xref)
|
|
209
|
+
# Bytes da imagem
|
|
210
|
+
image_bytes = base_image["image"]
|
|
211
|
+
# Extensão (jpg, png, etc.)
|
|
212
|
+
#image_ext = base_image["ext"]
|
|
213
|
+
except Exception as e:
|
|
214
|
+
print(e)
|
|
215
|
+
else:
|
|
216
|
+
img = ImageObject(image_bytes)
|
|
217
|
+
collection_imgs.append(img)
|
|
218
|
+
return collection_imgs
|
|
219
|
+
|
|
220
|
+
@classmethod
|
|
221
|
+
def create(cls, doc: DocumentPdf) -> ConvertPdfToImages:
|
|
222
|
+
_mod = ImplementConvertPdfFitz(doc)
|
|
223
|
+
return cls(_mod)
|
|
@@ -10,6 +10,9 @@ convert_stream.egg-info/SOURCES.txt
|
|
|
10
10
|
convert_stream.egg-info/dependency_links.txt
|
|
11
11
|
convert_stream.egg-info/requires.txt
|
|
12
12
|
convert_stream.egg-info/top_level.txt
|
|
13
|
+
convert_stream/convert/__init__.py
|
|
14
|
+
convert_stream/convert/image_to_pdf.py
|
|
15
|
+
convert_stream/convert/pdf_to_image.py
|
|
13
16
|
convert_stream/image/__init__.py
|
|
14
17
|
convert_stream/image/img_object.py
|
|
15
18
|
convert_stream/mod_types/__init__.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "convert_stream"
|
|
7
|
-
version = "2.5"
|
|
7
|
+
version = "2.5.1"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Bruno Chaves"},
|
|
10
10
|
]
|
|
@@ -30,6 +30,7 @@ dependencies = [
|
|
|
30
30
|
[tool.setuptools]
|
|
31
31
|
packages = [
|
|
32
32
|
"convert_stream",
|
|
33
|
+
"convert_stream.convert",
|
|
33
34
|
"convert_stream.mod_types",
|
|
34
35
|
"convert_stream.pdf",
|
|
35
36
|
"convert_stream.image",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|