Skip to content

Commit 8038110

Browse files
committed
rehaul all to accomodate newer changes in bernie
1 parent 2ffced6 commit 8038110

12 files changed

Lines changed: 112 additions & 475 deletions

‎mindee/image/extracted_image.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def write_to_file(self, output_path: Path | str, file_format: str | None = None)
6969
if file_format is None:
7070
out_file_path.write_bytes(self.buffer.read())
7171
else:
72-
image = bernard_image.decode(self.buffer)
72+
image = bernard_image.Image(self.buffer.read()) # type: ignore[call-arg]
7373
image.save(out_file_path, format=file_format)
7474
logger.info("File saved successfully to '%s'.", out_file_path)
7575
except Exception as e:

‎mindee/image/image_compressor.py‎

Lines changed: 0 additions & 39 deletions
This file was deleted.

‎mindee/image/image_extractor.py‎

Lines changed: 20 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -2,160 +2,51 @@
22

33
import io
44
from pathlib import Path
5-
from typing import BinaryIO
65

76
from mindee.dependencies import requires_bernard_ledit
87
from mindee.dependencies.checkers import BERNARD_LEDIT_AVAILABLE
98
from mindee.geometry.point import Point
10-
from mindee.geometry.polygon import Polygon, get_min_max_x, get_min_max_y
9+
from mindee.geometry.polygon import Polygon
1110
from mindee.image.extracted_image import ExtractedImage
1211
from mindee.input.local_input_source import LocalInputSource
1312

1413
if BERNARD_LEDIT_AVAILABLE:
1514
# pylint: disable=import-error
1615
import bernard_ledit.image as bernard_image
17-
import bernard_ledit.pdf as bernard_pdf
1816
else:
19-
bernard_pdf = None # type: ignore[assignment] # pylint: disable=invalid-name
2017
bernard_image = None # type: ignore[assignment] # pylint: disable=invalid-name
2118

2219

23-
@requires_bernard_ledit
24-
def _attach_image_as_new_file(
25-
input_buffer: BinaryIO,
26-
) -> bernard_pdf.PdfDocument:
27-
"""
28-
Attaches an image as a new page in a PdfDocument object.
29-
30-
:param input_buffer: Input buffer.
31-
:return: A PdfDocument handle.
32-
"""
33-
input_buffer.seek(0)
34-
pdf = bernard_pdf.PdfDocument.new()
35-
pdf.append_jpeg_page(input_buffer.read())
36-
return pdf
37-
38-
39-
@requires_bernard_ledit
40-
def extract_image_from_polygon(
41-
page_content: bernard_image.Image,
42-
polygon: list[Point],
43-
width: float,
44-
height: float,
45-
file_format: str,
46-
quality: int = 70,
47-
) -> BinaryIO:
48-
"""
49-
Crops the image from the given polygon.
50-
51-
:param page_content: Contents of the page as a Bernard L'Édit Image object.
52-
:param polygon: Polygon coordinates for the image.
53-
:param width: Width of the generated image.
54-
:param height: Height of the generated image.
55-
:param file_format: Format for the generated file.
56-
:param quality: JPEG quality for the output (default 70 — sufficient for OCR).
57-
:return: A generated image as a buffer.
58-
"""
59-
min_max_x = get_min_max_x(polygon)
60-
min_max_y = get_min_max_y(polygon)
61-
cropped_image = page_content.crop(
62-
left=int(min_max_x.min * width),
63-
top=int(min_max_y.min * height),
64-
right=int(min_max_x.max * width),
65-
bottom=int(min_max_y.max * height),
66-
)
67-
return _save_image_to_buffer(cropped_image, file_format, quality)
68-
69-
70-
@requires_bernard_ledit
71-
def _save_image_to_buffer(
72-
image: bernard_image.Image, file_format: str, quality: int = 70
73-
) -> BinaryIO:
74-
"""
75-
Saves an image as a buffer.
76-
77-
:param image: Bernard L'Édit wrapper for the image.
78-
:param file_format: Format to save the file as.
79-
:param quality: JPEG quality (default 70 — sufficient for OCR).
80-
:return: A valid buffer.
81-
"""
82-
buffer = io.BytesIO()
83-
image.save(buffer, format=file_format, quality=quality)
84-
buffer.seek(0)
85-
return buffer
86-
87-
88-
def get_file_extension(file_format: str):
89-
"""
90-
Extract the correct file extension.
91-
92-
:param file_format: Format of the file.
93-
:return: A valid file extension.
94-
"""
95-
return file_format.lower() if file_format != "JPEG" else "jpg"
96-
97-
9820
@requires_bernard_ledit
9921
def extract_multiple_images_from_source(
10022
input_source: LocalInputSource,
10123
page_id: int,
10224
polygons: list[Polygon | list[Point]],
103-
quality: int = 70,
10425
) -> list[ExtractedImage]:
10526
"""
106-
Extracts elements from a page based on a list of bounding boxes.
107-
108-
:param input_source: Local Input source to extract elements from.
109-
:param page_id: id of the page to extract from.
110-
:param polygons: List of coordinates to pull the elements from.
111-
:param quality: JPEG quality for extracted images (default 70).
112-
:return: List of byte arrays representing the extracted elements.
27+
Extract multiple images from a source.
28+
:param input_source: Source to extract images from.
29+
:param page_id: Page ID.
30+
:param polygons: List of polygons to extract.
31+
:return: List of extracted images.
11332
"""
11433
stem = Path(input_source.filename).stem
115-
doc = _load_pdf_doc(input_source)
116-
page_content = doc.rasterize_page(page_id, 100)
117-
width = doc.get_page(page_id).get_size().width
118-
height = doc.get_page(page_id).get_size().height
119-
120-
if input_source.is_pdf():
121-
file_format = "JPEG"
122-
else:
123-
input_source.file_object.seek(0)
124-
file_format = bernard_image.guess_format(input_source.file_object)
125-
126-
extracted_elements = []
127-
decoded_page = bernard_image.decode(page_content)
128-
for element_id, polygon in enumerate(polygons):
129-
image_data = extract_image_from_polygon(
130-
decoded_page,
131-
polygon,
132-
width,
133-
height,
134-
file_format,
135-
quality,
136-
)
137-
extracted_elements.append(
34+
input_source.file_object.seek(0)
35+
pts = [[(p.x, p.y) for p in poly] for poly in polygons]
36+
images = bernard_image.extract_polygons(input_source.file_object, page_id, pts) # type: ignore[attr-defined]
37+
38+
extracted = []
39+
for element_id, img in enumerate(images):
40+
buf = io.BytesIO()
41+
img.save(buf)
42+
fmt = str(img.format).lower() if img.format else "jpeg"
43+
fmt = fmt if fmt != "jpeg" else "jpg"
44+
extracted.append(
13845
ExtractedImage(
139-
image_data,
140-
f"{stem}_page-{(page_id + 1):03d}-item-{(element_id + 1):03d}."
141-
f"{get_file_extension(file_format)}",
46+
buf,
47+
f"{stem}_page-{page_id + 1:03d}-item-{element_id + 1:03d}.{fmt}",
14248
page_id,
14349
element_id,
14450
)
14551
)
146-
return extracted_elements
147-
148-
149-
@requires_bernard_ledit
150-
def _load_pdf_doc(input_file: LocalInputSource) -> bernard_pdf.PdfDocument:
151-
"""
152-
Loads a PDF document from a local input source.
153-
154-
:param input_file: Local input.
155-
:return: A valid PdfDocument handle.
156-
"""
157-
if input_file.is_pdf():
158-
input_file.file_object.seek(0)
159-
return bernard_pdf.PdfDocument(input_file.file_object.read())
160-
161-
return _attach_image_as_new_file(input_file.file_object)
52+
return extracted

‎mindee/input/local_input_source.py‎

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,15 @@
1010
from mindee.dependencies.checkers import BERNARD_LEDIT_AVAILABLE
1111
from mindee.error.mimetype_error import MimeTypeError
1212
from mindee.error.mindee_error import MindeeError, MindeeSourceError
13-
from mindee.image.image_compressor import compress_image
1413
from mindee.input.page_options import KEEP_ONLY, REMOVE, PageOptions
1514
from mindee.logger import logger
16-
from mindee.pdf.pdf_compressor import compress_pdf
1715
from mindee.pdf.pdf_utils import pdf_has_source_text
1816

1917
if BERNARD_LEDIT_AVAILABLE:
2018
# pylint: disable=import-error
21-
import bernard_ledit.pdf as bernard_pdf
19+
import bernard_ledit as bernard
2220
else:
23-
bernard_pdf = None # type: ignore[assignment] # pylint: disable=invalid-name
21+
bernard = None # type: ignore[assignment] # pylint: disable=invalid-name
2422

2523
mimetypes.add_type("image/heic", ".heic")
2624
mimetypes.add_type("image/heif", ".heif")
@@ -56,9 +54,9 @@ def __init__(self) -> None:
5654
# Some broken (yet fixable) PDFs can cause Bernard to crash on open.
5755
if BERNARD_LEDIT_AVAILABLE:
5856
try:
59-
pdf = bernard_pdf.PdfDocument(self.file_object)
57+
pdf = bernard.pdf.PdfDocument(self.file_object)
6058
self.page_count = len(pdf)
61-
except bernard_pdf.PdfiumError as e:
59+
except bernard.pdf.PdfiumError as e:
6260
logger.warning(
6361
"Could not open PDF file: %s due to %s", self.filename, e
6462
)
@@ -139,7 +137,7 @@ def apply_page_options(self, page_options: PageOptions) -> None:
139137
page_options.page_indexes,
140138
)
141139
self.file_object.seek(0)
142-
pdf = bernard_pdf.PdfDocument(self.file_object)
140+
pdf = bernard.pdf.PdfDocument(self.file_object)
143141
self.page_count = len(pdf)
144142
pdf.close()
145143

@@ -187,8 +185,8 @@ def merge_pdf_pages(self, page_numbers: set) -> None:
187185
:return: None
188186
"""
189187
self.file_object.seek(0)
190-
new_pdf = bernard_pdf.PdfDocument.new()
191-
pdf = bernard_pdf.PdfDocument(self.file_object)
188+
new_pdf = bernard.pdf.PdfDocument.new()
189+
pdf = bernard.pdf.PdfDocument(self.file_object)
192190
new_pdf.import_pages(pdf, list(page_numbers))
193191
self.file_object.close()
194192
bytes_io = io.BytesIO()
@@ -207,7 +205,7 @@ def is_pdf_empty(self) -> bool:
207205
:return: ``True`` if the PDF is empty
208206
"""
209207
self.file_object.seek(0)
210-
with bernard_pdf.PdfDocument(self.file_object) as pdf:
208+
with bernard.pdf.PdfDocument(self.file_object) as pdf:
211209
return pdf.has_no_content()
212210
raise MindeeSourceError(f"PDF couldn't be accessed: {self.filename}")
213211

@@ -248,8 +246,6 @@ def compress(
248246
quality: int = 85,
249247
max_width: int | None = None,
250248
max_height: int | None = None,
251-
force_source_text: bool = False,
252-
disable_source_text: bool = True,
253249
) -> None:
254250
"""
255251
Compresses the file object, either as a PDF or an image.
@@ -258,20 +254,17 @@ def compress(
258254
For PDFs, this affects image quality within the PDF.
259255
:param max_width: Maximum width for image resizing. Ignored for PDFs.
260256
:param max_height: Maximum height for image resizing. Ignored for PDFs.
261-
:param force_source_text: For PDFs, whether to force compression even if source text is present.
262-
:param disable_source_text: For PDFs, whether to disable source text during compression.
263257
"""
264-
new_file_bytes: bytes
258+
259+
self.file_object.seek(0)
260+
data = self.file_object.read()
265261
if self.is_pdf():
266-
new_file_bytes = compress_pdf(
267-
self.file_object, quality, force_source_text, disable_source_text
268-
)
262+
compressed = bernard.pdf.compress(data, quality)
269263
else:
270-
new_file_bytes = compress_image(
271-
self.file_object, quality, max_width, max_height
272-
)
264+
compressed = bernard.image.compress(data, quality, max_width, max_height)
273265

274-
self.file_object = io.BytesIO(new_file_bytes)
266+
self.file_object = io.BytesIO(compressed)
267+
self.file_object.seek(0)
275268

276269
def __enter__(self):
277270
"""Allows the class to be used as a context manager."""

‎mindee/pdf/__init__.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
from mindee.pdf.pdf_compressor import compress_pdf
21
from mindee.pdf.pdf_utils import (
32
lerp,
43
pdf_has_source_text,
54
)
65

76
__all__ = [
8-
"compress_pdf",
97
"lerp",
108
"pdf_has_source_text",
119
]

0 commit comments

Comments
 (0)