| import gradio as gr |
| import fitz |
| import csv |
| import tempfile |
| import os |
|
|
| def analyze_pdf(file_obj): |
| if file_obj is None: |
| return "ファイルをアップロードしてください", None |
| |
| doc = fitz.open(file_obj.name) |
| temp_dir = tempfile.mkdtemp() |
| |
| results = [] |
| full_text_order = [] |
| |
| for page_num in range(len(doc)): |
| page = doc[page_num] |
| blocks = page.get_text("rawdict")["blocks"] |
| char_idx = 0 |
| for b_idx, block in enumerate(blocks): |
| if "lines" not in block: |
| continue |
| for l_idx, line in enumerate(block["lines"]): |
| for s_idx, span in line["spans"]: |
| font = span.get("font", "") |
| for char in span["chars"]: |
| c = char["c"] |
| bbox = char["bbox"] |
| results.append({ |
| "index": char_idx, |
| "char": c, |
| "x0": round(bbox[0], 2), |
| "y0": round(bbox[1], 2), |
| "x1": round(bbox[2], 2), |
| "y1": round(bbox[3], 2), |
| "block": b_idx, |
| "line": l_idx, |
| "span": s_idx, |
| "font": font, |
| }) |
| full_text_order.append(c) |
| char_idx += 1 |
| |
| doc.close() |
| |
| csv_path = os.path.join(temp_dir, "char_order.csv") |
| with open(csv_path, "w", encoding="utf-8-sig", newline="") as f: |
| writer = csv.DictWriter(f, fieldnames=["index","char","x0","y0","x1","y1","block","line","span","font"]) |
| writer.writeheader() |
| writer.writerows(results) |
| |
| |
| preview = "".join(full_text_order[:500]) |
| summary = f"総文字数: {len(full_text_order)}\n\n抽出順テキスト(先頭500文字):\n{preview}" |
| |
| return summary, csv_path |
|
|
| with gr.Blocks(title="PDF文字順序解析") as demo: |
| gr.Markdown("## PDF文字抽出順序の解析") |
| gr.Markdown("PDFをアップロードすると、内部のテキスト抽出順序をCSVで出力します") |
| |
| with gr.Row(): |
| file_input = gr.File(label="PDFファイル", file_types=[".pdf"], type="file") |
| |
| run_btn = gr.Button("解析実行", variant="primary") |
| summary_box = gr.Textbox(label="結果サマリ", lines=15) |
| csv_output = gr.File(label="文字順序CSV") |
| |
| run_btn.click(fn=analyze_pdf, inputs=[file_input], outputs=[summary_box, csv_output]) |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|