File size: 3,551 Bytes
c03caab
62927c1
 
 
 
 
c03caab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import gradio as gr
try:
    import fitz  # from PyMuPDF
except ImportError:
    raise ImportError("PyMuPDF is not installed. Make sure to include 'pymupdf' in your requirements.txt.")

import numpy as np
import pandas as pd
from PIL import Image
import io

def extract_pdf_images(pdf_bytes):
    doc = fitz.open(stream=pdf_bytes, filetype="pdf")
    images = []
    for page in doc:
        pix = page.get_pixmap(matrix=fitz.Matrix(2, 2))
        img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
        images.append(img)
    return images

def calculate_area(drawing_data, page_number, pdf_file, area_type):
    if drawing_data is None or "layers" not in drawing_data:
        return None, "No drawing found.", None

    try:
        coords = []
        for layer in drawing_data["layers"]:
            for shape in layer["paths"]:
                if shape["type"] == "polygon":
                    coords.extend([[pt["x"], pt["y"]] for pt in shape["points"]])

        coords = np.array(coords)
        if len(coords) < 3:
            return None, "Draw a closed polygon to calculate area.", None

        area_px = 0.5 * np.abs(np.dot(coords[:, 0], np.roll(coords[:, 1], 1)) -
                               np.dot(coords[:, 1], np.roll(coords[:, 0], 1)))
        area_sft = area_px / (96**2) * 144

        rd_label = f"Page {page_number + 1}"
        result_df = pd.DataFrame([{
            "RD": rd_label,
            "Area Type": area_type,
            "Area (sq.ft)": round(area_sft, 2)
        }])

        excel_io = io.BytesIO()
        with pd.ExcelWriter(excel_io, engine="openpyxl") as writer:
            result_df.to_excel(writer, index=False, sheet_name="Area Summary")
        excel_bytes = excel_io.getvalue()

        return f"Estimated {area_type}: {area_sft:.2f} sq.ft", None, excel_bytes
    except Exception as e:
        return None, str(e), None

with gr.Blocks() as demo:
    gr.Markdown("## ๐Ÿ“ Canal Cross Section Area Calculator (Gradio Version)")
    gr.Markdown("Upload a multi-page PDF of canal cross sections. Select a page, draw polygon on the image, and compute area (in sqft).")

    pdf_input = gr.File(label="๐Ÿ“„ Upload PDF", type="binary")
    area_type = gr.Radio(choices=["Cutting Area", "Filling Area"], value="Cutting Area", label="Area Type")
    page_slider = gr.Slider(minimum=0, maximum=0, step=1, label="Select Page")
    image_display = gr.Image(label="Cross Section Page", interactive=False)
    drawing = gr.Sketchpad(label="Draw Area on Image", shape="polygon")
    calculate_btn = gr.Button("๐Ÿงฎ Calculate Area")
    result_text = gr.Textbox(label="Result")
    download_excel = gr.File(label="๐Ÿ“ฅ Download Excel", interactive=False)
    error_output = gr.Textbox(label="Errors", visible=False)

    def load_pdf(pdf_file):
        if pdf_file is None:
            return gr.Image.update(value=None), gr.update(maximum=0), None
        images = extract_pdf_images(pdf_file)
        return images[0], gr.update(maximum=len(images) - 1), images

    def update_page(images, page_index):
        return images[page_index]

    pdf_file_state = gr.State()
    images_state = gr.State()

    pdf_input.change(load_pdf, inputs=[pdf_input], outputs=[image_display, page_slider, images_state])
    page_slider.change(update_page, inputs=[images_state, page_slider], outputs=image_display)

    calculate_btn.click(
        calculate_area,
        inputs=[drawing, page_slider, pdf_input, area_type],
        outputs=[result_text, error_output, download_excel]
    )

demo.launch()