Spaces:
Running
Running
Commit ·
3d1f0a3
1
Parent(s): 32ac972
sizing interface
Browse files
app.py
CHANGED
|
@@ -12,6 +12,27 @@ from stl_slicer import SliceStack, load_mesh, slice_stl_to_tiffs
|
|
| 12 |
ViewerState = dict[str, Any]
|
| 13 |
SAMPLE_STL_FILENAMES = ("Hollow_Pyramid.stl", "balanced_die.stl", "halfsphere.stl")
|
| 14 |
SAMPLE_STL_DIR = Path(__file__).resolve().parent / "sample_stls"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
|
| 17 |
def _read_slice_preview(path: str) -> Image.Image:
|
|
@@ -34,21 +55,6 @@ def _stack_to_state(stack: SliceStack) -> ViewerState:
|
|
| 34 |
}
|
| 35 |
|
| 36 |
|
| 37 |
-
def _format_summary(stack: SliceStack, source_name: str) -> str:
|
| 38 |
-
(x_min, y_min, z_min), (x_max, y_max, z_max) = stack.bounds
|
| 39 |
-
return "\n".join(
|
| 40 |
-
[
|
| 41 |
-
"### Slice Stack Ready",
|
| 42 |
-
f"- Source: `{source_name}`",
|
| 43 |
-
f"- TIFF count: `{len(stack.tiff_paths)}`",
|
| 44 |
-
f"- Image size: `{stack.image_size[0]} x {stack.image_size[1]}` pixels",
|
| 45 |
-
f"- Layer height: `{stack.layer_height}`",
|
| 46 |
-
f"- Pixel size: `{stack.pixel_size}`",
|
| 47 |
-
f"- Bounds: `x={x_min:.3f}..{x_max:.3f}`, `y={y_min:.3f}..{y_max:.3f}`, `z={z_min:.3f}..{z_max:.3f}`",
|
| 48 |
-
]
|
| 49 |
-
)
|
| 50 |
-
|
| 51 |
-
|
| 52 |
def _format_model_details(source_name: str, mesh) -> str:
|
| 53 |
extents = mesh.extents
|
| 54 |
return "\n".join(
|
|
@@ -138,7 +144,6 @@ def generate_all_stacks(
|
|
| 138 |
for stl_file in files:
|
| 139 |
if not stl_file:
|
| 140 |
results.extend([
|
| 141 |
-
"No file uploaded.",
|
| 142 |
_empty_state(),
|
| 143 |
_reset_slider(),
|
| 144 |
"No slice stack loaded yet.",
|
|
@@ -171,7 +176,6 @@ def generate_all_stacks(
|
|
| 171 |
interactive=len(stack.tiff_paths) > 1,
|
| 172 |
)
|
| 173 |
results.extend([
|
| 174 |
-
_format_summary(stack, Path(stl_file).name),
|
| 175 |
state,
|
| 176 |
slider,
|
| 177 |
label,
|
|
@@ -198,7 +202,7 @@ def shift_slice(state: ViewerState, index: float, delta: int) -> tuple[int, str,
|
|
| 198 |
|
| 199 |
|
| 200 |
def build_demo() -> gr.Blocks:
|
| 201 |
-
with gr.Blocks(title="STL TIFF Slicer") as demo:
|
| 202 |
gr.Markdown(
|
| 203 |
"""
|
| 204 |
# STL to TIFF Slicer
|
|
@@ -232,7 +236,7 @@ def build_demo() -> gr.Blocks:
|
|
| 232 |
label=f"3D Viewer {i + 1}",
|
| 233 |
display_mode="solid",
|
| 234 |
clear_color=(0.94, 0.95, 0.97, 1.0),
|
| 235 |
-
height=
|
| 236 |
)
|
| 237 |
model_details = gr.Markdown(f"No model {i + 1} loaded.")
|
| 238 |
stl_files.append(stl_file)
|
|
@@ -248,7 +252,6 @@ def build_demo() -> gr.Blocks:
|
|
| 248 |
# --- Per-object slice browsers ---
|
| 249 |
states: list[gr.State] = []
|
| 250 |
sliders: list[gr.Slider] = []
|
| 251 |
-
summaries: list[gr.Markdown] = []
|
| 252 |
slice_labels: list[gr.Markdown] = []
|
| 253 |
slice_previews: list[gr.Image] = []
|
| 254 |
download_zips: list[gr.File] = []
|
|
@@ -256,13 +259,12 @@ def build_demo() -> gr.Blocks:
|
|
| 256 |
with gr.Row():
|
| 257 |
for i in range(3):
|
| 258 |
with gr.Column():
|
| 259 |
-
summary = gr.Markdown(f"Upload STL {i + 1} to begin.")
|
| 260 |
slice_label = gr.Markdown("No slice stack loaded yet.")
|
| 261 |
slice_preview = gr.Image(
|
| 262 |
label=f"Slice Preview {i + 1}",
|
| 263 |
type="pil",
|
| 264 |
image_mode="L",
|
| 265 |
-
height=
|
| 266 |
)
|
| 267 |
with gr.Row():
|
| 268 |
prev_button = gr.Button("\u25c4 Prev")
|
|
@@ -278,7 +280,6 @@ def build_demo() -> gr.Blocks:
|
|
| 278 |
download_zip = gr.File(label=f"Download TIFF ZIP {i + 1}")
|
| 279 |
state = gr.State(_empty_state())
|
| 280 |
|
| 281 |
-
summaries.append(summary)
|
| 282 |
slice_labels.append(slice_label)
|
| 283 |
slice_previews.append(slice_preview)
|
| 284 |
sliders.append(slice_slider)
|
|
@@ -316,7 +317,6 @@ def build_demo() -> gr.Blocks:
|
|
| 316 |
generate_outputs: list = []
|
| 317 |
for i in range(3):
|
| 318 |
generate_outputs.extend([
|
| 319 |
-
summaries[i],
|
| 320 |
states[i],
|
| 321 |
sliders[i],
|
| 322 |
slice_labels[i],
|
|
|
|
| 12 |
ViewerState = dict[str, Any]
|
| 13 |
SAMPLE_STL_FILENAMES = ("Hollow_Pyramid.stl", "balanced_die.stl", "halfsphere.stl")
|
| 14 |
SAMPLE_STL_DIR = Path(__file__).resolve().parent / "sample_stls"
|
| 15 |
+
APP_CSS = """
|
| 16 |
+
.gradio-container {
|
| 17 |
+
font-size: 90%;
|
| 18 |
+
padding-top: 0.5rem !important;
|
| 19 |
+
padding-bottom: 0.5rem !important;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
.gradio-container .gr-row {
|
| 23 |
+
gap: 0.5rem !important;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
.gradio-container .gr-form,
|
| 27 |
+
.gradio-container .gr-box,
|
| 28 |
+
.gradio-container .block {
|
| 29 |
+
padding: 0.4rem !important;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
.gradio-container .prose {
|
| 33 |
+
margin-bottom: 0.4rem !important;
|
| 34 |
+
}
|
| 35 |
+
"""
|
| 36 |
|
| 37 |
|
| 38 |
def _read_slice_preview(path: str) -> Image.Image:
|
|
|
|
| 55 |
}
|
| 56 |
|
| 57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
def _format_model_details(source_name: str, mesh) -> str:
|
| 59 |
extents = mesh.extents
|
| 60 |
return "\n".join(
|
|
|
|
| 144 |
for stl_file in files:
|
| 145 |
if not stl_file:
|
| 146 |
results.extend([
|
|
|
|
| 147 |
_empty_state(),
|
| 148 |
_reset_slider(),
|
| 149 |
"No slice stack loaded yet.",
|
|
|
|
| 176 |
interactive=len(stack.tiff_paths) > 1,
|
| 177 |
)
|
| 178 |
results.extend([
|
|
|
|
| 179 |
state,
|
| 180 |
slider,
|
| 181 |
label,
|
|
|
|
| 202 |
|
| 203 |
|
| 204 |
def build_demo() -> gr.Blocks:
|
| 205 |
+
with gr.Blocks(title="STL TIFF Slicer", css=APP_CSS) as demo:
|
| 206 |
gr.Markdown(
|
| 207 |
"""
|
| 208 |
# STL to TIFF Slicer
|
|
|
|
| 236 |
label=f"3D Viewer {i + 1}",
|
| 237 |
display_mode="solid",
|
| 238 |
clear_color=(0.94, 0.95, 0.97, 1.0),
|
| 239 |
+
height=270,
|
| 240 |
)
|
| 241 |
model_details = gr.Markdown(f"No model {i + 1} loaded.")
|
| 242 |
stl_files.append(stl_file)
|
|
|
|
| 252 |
# --- Per-object slice browsers ---
|
| 253 |
states: list[gr.State] = []
|
| 254 |
sliders: list[gr.Slider] = []
|
|
|
|
| 255 |
slice_labels: list[gr.Markdown] = []
|
| 256 |
slice_previews: list[gr.Image] = []
|
| 257 |
download_zips: list[gr.File] = []
|
|
|
|
| 259 |
with gr.Row():
|
| 260 |
for i in range(3):
|
| 261 |
with gr.Column():
|
|
|
|
| 262 |
slice_label = gr.Markdown("No slice stack loaded yet.")
|
| 263 |
slice_preview = gr.Image(
|
| 264 |
label=f"Slice Preview {i + 1}",
|
| 265 |
type="pil",
|
| 266 |
image_mode="L",
|
| 267 |
+
height=324,
|
| 268 |
)
|
| 269 |
with gr.Row():
|
| 270 |
prev_button = gr.Button("\u25c4 Prev")
|
|
|
|
| 280 |
download_zip = gr.File(label=f"Download TIFF ZIP {i + 1}")
|
| 281 |
state = gr.State(_empty_state())
|
| 282 |
|
|
|
|
| 283 |
slice_labels.append(slice_label)
|
| 284 |
slice_previews.append(slice_preview)
|
| 285 |
sliders.append(slice_slider)
|
|
|
|
| 317 |
generate_outputs: list = []
|
| 318 |
for i in range(3):
|
| 319 |
generate_outputs.extend([
|
|
|
|
| 320 |
states[i],
|
| 321 |
sliders[i],
|
| 322 |
slice_labels[i],
|