pdfgen/analyze_pdf.py
2025-08-16 07:28:01 +00:00

133 lines
6.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import fitz # PyMuPDF
import sys
import json
import os
def analyze_pdf_to_json(pdf_path):
"""
Анализирует PDF-файл, извлекает всю текстовую разметку, шрифты,
координаты графика и создает готовый map.json файл.
"""
try:
doc = fitz.open(pdf_path)
print(f"--- Analyzing PDF: {pdf_path} ({len(doc)} pages) ---")
except Exception as e:
print(f"Error opening file: {e}")
return
# --- 1. АВТОМАТИЧЕСКИ СОБИРАЕМ ВСЕ УНИКАЛЬНЫЕ ШРИФТЫ ---
unique_fonts = set()
for page in doc:
fonts_on_page = page.get_fonts(full=False)
for font_info in fonts_on_page:
unique_fonts.add(font_info[3]) # font_info[3] - это имя шрифта
# Сортируем для стабильного порядка и создаем карту "имя -> ifont"
# Начинаем ifont с 1, так как ifont: 0 мы зарезервируем для Helvetica
sorted_fonts = sorted(list(unique_fonts))
font_map = {font_name: index + 1 for index, font_name in enumerate(sorted_fonts)}
print("\n--- Found Unique Fonts ---")
print("This is your 'font_map'. Use it to configure font loading in routes.js:")
print(json.dumps(font_map, indent=2))
print("--------------------------\n")
# --- 2. ИЩЕМ ПРЯМОУГОЛЬНИК ГРАФИКА НА ПЕРВОЙ СТРАНИЦЕ ---
chart_area_rect = None
if len(doc) > 0:
target_page = doc[0]
paths = target_page.get_drawings()
max_area = 0
# Ищем самый большой прямоугольник, который не занимает всю страницу
page_area = target_page.rect.width * target_page.rect.height
for path in paths:
# Ищем прямоугольники (type 's' с одним элементом 're')
if path["type"] == "s" and len(path["items"]) == 1 and path["items"][0][0] == "re":
rect = fitz.Rect(path["rect"])
area = rect.width * rect.height
if area > max_area and area < (page_area * 0.9): # Игнорируем прямоугольники, занимающие почти всю страницу
max_area = area
chart_area_rect = rect
# --- 3. Создаем базовую структуру для JSON-файла ---
output_data = {
"font_map": font_map,
"constants": {},
"replacements_template": {},
"map": []
}
if chart_area_rect:
print(f"--- Found Chart Area Rectangle ---")
print(chart_area_rect)
print("--------------------------------\n")
output_data["constants"]["bar_chart_x_ill"] = round(chart_area_rect.x0, 2)
output_data["constants"]["bar_chart_y_ill"] = round(chart_area_rect.y0, 2)
output_data["constants"]["bar_chart_width"] = round(chart_area_rect.width, 2)
output_data["constants"]["bar_chart_height"] = round(chart_area_rect.height, 2)
output_data["constants"]["bar_chart_max_cost"] = 200 # Пример, это значение лучше задавать вручную
# --- 4. ИЗВЛЕКАЕМ ВЕСЬ ТЕКСТ И ЕГО СВОЙСТВА ---
all_found_texts = set()
for page_num in range(len(doc)):
page = doc[page_num]
# Используем get_text("dict") для получения детальной информации
blocks = page.get_text("dict", flags=fitz.TEXTFLAGS_SEARCH)["blocks"]
for block in blocks:
if "lines" in block:
for line in block["lines"]:
# Собираем текст из спанов, чтобы обрабатывать сгруппированные строки
full_line_text = "".join(span["text"] for span in line["spans"]).strip()
if full_line_text:
all_found_texts.add(full_line_text)
# Итерируем по отдельным спанам для точной разметки
for span in line["spans"]:
text = span["text"].strip()
if not text:
continue
font_name = span["font"]
font_size = span["size"]
bbox = span["bbox"] # (x0, y0, x1, y1) от левого верхнего угла
ifont = font_map.get(font_name, 0)
map_item = {
"ipage": page_num,
"field": text,
"x_ill": round(bbox[0], 2),
"y_ill": round(bbox[1], 2),
"size": round(font_size, 2),
"ifont": ifont
}
output_data["map"].append(map_item)
doc.close()
# Заполняем replacements_template, чтобы пользователь мог указать имена переменных
output_data["replacements_template"] = {text: "" for text in sorted(list(all_found_texts))}
# --- 5. СОХРАНЯЕМ РЕЗУЛЬТАТ В JSON ---
base_name = os.path.splitext(os.path.basename(pdf_path))[0]
output_filename = f"{base_name.replace('_original', '')}.map.json"
try:
with open(output_filename, 'w', encoding='utf-8') as f:
json.dump(output_data, f, indent=2, ensure_ascii=False)
print(f"--- SUCCESS ---")
print(f"Successfully created JSON map file: {output_filename}")
print(f"Please review this file and fill in the variable names in 'replacements_template'.")
except Exception as e:
print(f"Error writing JSON file: {e}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python analyze_pdf.py <path_to_pdf_template>")
sys.exit(1)
pdf_path = sys.argv[1]
analyze_pdf_to_json(pdf_path)