feat: implement custom STL preview renderer from scratch#1429
feat: implement custom STL preview renderer from scratch#1429ludvig-sandh wants to merge 1 commit into
Conversation
Computerdores
left a comment
There was a problem hiding this comment.
read over the loading code out of curiosity and wrote down some thoughts I had
Note that I didn't think about it particularly long, so take these for the not-thought-through thoughts that they are :)
| if len(header) < _BINARY_STL_HEADER_SIZE: | ||
| raise StlRenderError("STL file is too small") | ||
|
|
||
| triangle_count = struct.unpack_from("<I", header, 80)[0] |
There was a problem hiding this comment.
move the 80 to a constant to document what it represents
| def _read_stl_header(filepath: Path) -> bytes: | ||
| with filepath.open("rb") as file: | ||
| return file.read(_BINARY_STL_HEADER_SIZE) |
There was a problem hiding this comment.
this seems unnecessary to me
| if triangle_count > max_triangles: | ||
| raise StlRenderError("STL file contains too many triangles") |
There was a problem hiding this comment.
this is duplicated and seems like it should be right after the triangle count is retrieved
|
|
||
| data = filepath.read_bytes() | ||
| trailing = data[expected_size:] if expected_size <= file_size else b"" | ||
| if expected_size < file_size and not trailing.strip(b"\x00\r\n\t "): |
There was a problem hiding this comment.
this way of detecting that it's an ascii variant seems scuffed
|
@Computerdores thanks for the review! Good points :) Well, do we want to move forward with this approach? There's no point in polishing experimental code until we aim to use it. |
|
yeah my take is pretty much the same as Cyan's, only thing I am unsure about is the performance Footnotes
|

Summary
This PR experiments with a custom renderer for STL file previews (#351).
STL files only contain triangle information. No shading, material or light, which makes them pretty easy to parse. STL files are pretty rigid and come in two main formats: binary and ASCII. I handle both, then parse the triangles, compute normals (for lighting), project onto 2d, then draw onto a PIL image.
Pros:
Cons:
For now it is still an experiment (hence draft), so I have included some benchmarking code for tracking rendering times. My investigation shows roughly:
small files (0-2000 triangles): <80ms
medium files (2000-100,000): <1000ms
large files (100,000+): several seconds
For now I set a tri count cap of 100,000 and don't render anything above. Eventually the cap should be configurable.
It is also possible to approximate the rendering by reducing the triangle counts (only use a subset of them), but this didn't look good as the objects had visible holes in them.
This is what it looks like (two of the bottom files are not rendered due to the cap):

From my very short and limited testing the renders looks good enough, and the rendering seems performant enough for users to benefit from the feature. Especially with the tri count cap, as well as concurrently rendering many files at a time. Obviously we may need some more rigorous testing to make sure it works well (eg. on low-end systems).
Although I haven't done any research, I can image most STL files being pretty small. Especially if you have many enough to use TagStudio to organize them. If that's true, a slower renderer that by default only renders smaller STL files might work well for now.
Tasks Completed