build123d icon indicating copy to clipboard operation
build123d copied to clipboard

add BytesIO support to all export functions (STL, STEP, etc)

Open jdegenstein opened this issue 5 months ago • 2 comments

Currently export_brep supports BytesIO export, consider adding to other export functions. It may make upcoming wasm in-browser usage easier.

ref: https://github.com/yeicor/OCP.wasm/issues/4

jdegenstein avatar Jul 01 '25 17:07 jdegenstein

BytesIO support for gltf would be a big help for me as well

wedward avatar Jul 25 '25 17:07 wedward

+1 for gltf in particular as it is the preferred format for threejs. stl would also be useful to me.

goertzenator avatar Nov 08 '25 17:11 goertzenator

OK I have done further research and testing, and here is the current state of this proposal (has not been put into build123d yet, just local work). I am particularly disappointed that we don't have an OCCT-native solution for GLTF. It appears that OCCT simply does not support std::ostream for many of the exporter file formats.

file format ability to export to BytesIO
BREP ✅ already implemented
SVG ✅ tested and working
DXF ✅ tested and working
STEP ✅ tested and working
STL ❌ not possible with OCCT
GLTF/GLB ❌ not possible with OCCT
STL ✅ tested and working using lib3mf / Mesher
3MF ✅ tested and working using lib3mf / Mesher

jdegenstein avatar Nov 17 '25 19:11 jdegenstein

After consulting with ChatGPT on this the following seems like it might be an acceptable solution the the STL and GLTF/GLB case:

import io
import os
import tempfile
import sys
from OCP.StlAPI import StlAPI_Writer

def write_stl_to_memory(shape, binary=True) -> io.BytesIO:
    """Write shape to STL entirely in memory (best-effort cross-platform)."""
    writer = StlAPI_Writer()
    writer.ASCIIMode(not binary)

    # --- Linux fast path ---
    if hasattr(os, "memfd_create"):
        fd = os.memfd_create("stl_buffer")
        tmp_path = f"/proc/self/fd/{fd}"
        writer.Write(shape, tmp_path)
        os.lseek(fd, 0, os.SEEK_SET)
        data = os.read(fd, 1 << 24)  # read up to 16 MB; adjust as needed
        os.close(fd)
        return io.BytesIO(data)

    # --- macOS / Windows fallback ---
    with tempfile.SpooledTemporaryFile(max_size=64 * 1024 * 1024) as tmp:
        tmp_name = tmp.name if tmp.name else "tmp.stl"
        writer.Write(shape, tmp_name)
        tmp.seek(0)
        data = tmp.read()
    return io.BytesIO(data)

gumyr avatar Nov 17 '25 21:11 gumyr

OK as of the above merged PR, here is the current status:

file format ability to export to BytesIO
BREP ✅ already released
SVG ✅ merged in PR #1141
DXF ✅ merged in PR #1141
STEP ✅ merged in PR #1141
STL ❌ not possible with OCCT
GLTF/GLB ❌ not possible with OCCT
STL ✅ merged in PR #1141 using lib3mf / Mesher.write_stream
3MF ✅ merged in PR #1141 using lib3mf / Mesher.write_stream

As such, I have decided to keep this issue open (with an updated title). The major missing piece is GLTF/GLB, per the linked issue at OCCT it sounds like they have added this (and STL, maybe others) to their roadmap.

jdegenstein avatar Nov 20 '25 22:11 jdegenstein