Fixed columnless format issue
This commit is contained in:
@@ -107,49 +107,89 @@ class NativePDFService:
|
|||||||
|
|
||||||
def _extract_text_blocks(self, doc_page: DocumentPage, page: fitz.Page) -> None:
|
def _extract_text_blocks(self, doc_page: DocumentPage, page: fitz.Page) -> None:
|
||||||
"""Extract text blocks with positioning and font information."""
|
"""Extract text blocks with positioning and font information."""
|
||||||
blocks = page.get_text("dict", flags=fitz.TEXT_PRESERVE_WHITESPACE)["blocks"]
|
blocks = page.get_text("rawdict")["blocks"]
|
||||||
sequence = 0
|
sequence = 0
|
||||||
|
chunks = []
|
||||||
|
|
||||||
for block in blocks:
|
for block in blocks:
|
||||||
if block["type"] != 0: # Skip non-text blocks
|
if block["type"] != 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
block_text_parts = []
|
current_chunk = None
|
||||||
font_info = {"family": None, "size": None, "color": None, "style": None}
|
space_count = 0
|
||||||
|
|
||||||
for line in block.get("lines", []):
|
for line in block.get("lines", []):
|
||||||
for span in line.get("spans", []):
|
for span in line.get("spans", []):
|
||||||
text = span.get("text", "").strip()
|
font_size = span.get("size", 12.0)
|
||||||
if text:
|
space_threshold = font_size * 1.5
|
||||||
block_text_parts.append(text)
|
|
||||||
# Capture font info from the first non-empty span
|
font_family = span.get("font", None)
|
||||||
if font_info["family"] is None:
|
color_int = span.get("color", 0)
|
||||||
font_info["family"] = span.get("font", None)
|
font_color = f"#{color_int:06x}" if isinstance(color_int, int) else None
|
||||||
font_info["size"] = span.get("size", None)
|
|
||||||
color_int = span.get("color", 0)
|
flags = span.get("flags", 0)
|
||||||
font_info["color"] = f"#{color_int:06x}" if isinstance(color_int, int) else None
|
styles = []
|
||||||
flags = span.get("flags", 0)
|
if flags & 1: styles.append("superscript")
|
||||||
styles = []
|
if flags & 2: styles.append("italic")
|
||||||
if flags & 1:
|
if flags & 4: styles.append("serif")
|
||||||
styles.append("superscript")
|
if flags & 8: styles.append("monospace")
|
||||||
if flags & 2:
|
if flags & 16: styles.append("bold")
|
||||||
styles.append("italic")
|
font_style = ",".join(styles) if styles else "regular"
|
||||||
if flags & 4:
|
|
||||||
styles.append("serif")
|
font_info = {
|
||||||
if flags & 8:
|
"family": font_family,
|
||||||
styles.append("monospace")
|
"size": font_size,
|
||||||
if flags & 16:
|
"color": font_color,
|
||||||
styles.append("bold")
|
"style": font_style
|
||||||
font_info["style"] = ",".join(styles) if styles else "regular"
|
}
|
||||||
|
|
||||||
|
for char in span.get("chars", []):
|
||||||
|
c = char["c"]
|
||||||
|
bbox = char["bbox"]
|
||||||
|
|
||||||
|
if c == ' ':
|
||||||
|
space_count += 1
|
||||||
|
if space_count >= 2:
|
||||||
|
if current_chunk and current_chunk["text"].strip():
|
||||||
|
chunks.append(current_chunk)
|
||||||
|
current_chunk = None
|
||||||
|
elif current_chunk:
|
||||||
|
current_chunk["text"] += c
|
||||||
|
current_chunk["bbox"][2] = max(current_chunk["bbox"][2], bbox[2])
|
||||||
|
current_chunk["bbox"][3] = max(current_chunk["bbox"][3], bbox[3])
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
space_count = 0
|
||||||
|
|
||||||
|
if current_chunk is None:
|
||||||
|
current_chunk = {"text": c, "bbox": list(bbox), "font_info": font_info}
|
||||||
|
continue
|
||||||
|
|
||||||
|
prev_x1 = current_chunk["bbox"][2]
|
||||||
|
distance = bbox[0] - prev_x1
|
||||||
|
|
||||||
|
if distance > space_threshold:
|
||||||
|
if current_chunk["text"].strip():
|
||||||
|
chunks.append(current_chunk)
|
||||||
|
current_chunk = {"text": c, "bbox": list(bbox), "font_info": font_info}
|
||||||
|
else:
|
||||||
|
current_chunk["text"] += c
|
||||||
|
current_chunk["bbox"][2] = max(current_chunk["bbox"][2], bbox[2])
|
||||||
|
current_chunk["bbox"][3] = max(current_chunk["bbox"][3], bbox[3])
|
||||||
|
current_chunk["bbox"][1] = min(current_chunk["bbox"][1], bbox[1])
|
||||||
|
current_chunk["bbox"][0] = min(current_chunk["bbox"][0], bbox[0])
|
||||||
|
|
||||||
full_text = " ".join(block_text_parts)
|
if current_chunk and current_chunk["text"].strip():
|
||||||
if not full_text.strip():
|
chunks.append(current_chunk)
|
||||||
continue
|
current_chunk = None
|
||||||
|
|
||||||
bbox = block["bbox"]
|
for chunk in chunks:
|
||||||
|
bbox = chunk["bbox"]
|
||||||
|
font_info = chunk["font_info"]
|
||||||
|
|
||||||
self.text_block_repo.create_text_block(
|
self.text_block_repo.create_text_block(
|
||||||
page_id=doc_page.id,
|
page_id=doc_page.id,
|
||||||
text=full_text,
|
text=chunk["text"].strip(),
|
||||||
x=bbox[0],
|
x=bbox[0],
|
||||||
y=bbox[1],
|
y=bbox[1],
|
||||||
width=bbox[2] - bbox[0],
|
width=bbox[2] - bbox[0],
|
||||||
|
|||||||
Reference in New Issue
Block a user