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 ") sys.exit(1) pdf_path = sys.argv[1] analyze_pdf_to_json(pdf_path)