mirror of
https://github.com/yeicor-3d/yet-another-cad-viewer.git
synced 2025-12-19 22:24:17 +01:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea181dac0b | ||
|
|
09525daae8 | ||
|
|
874f9e8d6e | ||
|
|
822672c288 | ||
|
|
383586c5a4 | ||
|
|
b4d557534d | ||
|
|
e6921144fb | ||
|
|
f95509f4f4 | ||
|
|
5a0228d4fc | ||
|
|
5c96e4e44b | ||
|
|
4012bac31f | ||
|
|
4439c436fc | ||
|
|
b23119e44c | ||
|
|
e428d9cb5a | ||
|
|
6574db6f81 | ||
|
|
844d25483f | ||
|
|
2f6e7def42 | ||
|
|
dbf29c02a9 | ||
|
|
8303dd2d37 | ||
|
|
3e24a29e73 | ||
|
|
e3b32a7e92 | ||
|
|
20def41a6c | ||
|
|
aff3a367e6 | ||
|
|
80c94fec80 | ||
|
|
2d8d8178ba | ||
|
|
6ac1365e27 | ||
|
|
ef3938ca4a | ||
|
|
334a23c04d | ||
|
|
57be98ede3 | ||
|
|
52f97963f0 | ||
|
|
61a3f157ac | ||
|
|
bf4bf38dd2 | ||
|
|
4119656f69 | ||
|
|
3834e8d506 | ||
|
|
b4380d3a2f | ||
|
|
22ea0617e2 | ||
|
|
09c0994a34 | ||
|
|
0939e25da2 | ||
|
|
712e0a06e6 | ||
|
|
e73f745800 | ||
|
|
773ea797a1 | ||
|
|
aae20aeedf | ||
|
|
a3004e59fb | ||
|
|
5e76193f43 | ||
|
|
50a2627b55 | ||
|
|
cbddacb7b8 | ||
|
|
887e71b7b2 |
10
README.md
10
README.md
@@ -21,8 +21,14 @@ in a web browser.
|
||||
The [example](example) is a fully working project that shows how to use the viewer.
|
||||
|
||||
You can play with the latest
|
||||
demo [here](https://yeicor-3d.github.io/yet-another-cad-viewer/?preload=logo.glb&preload=fox.glb&preload=img.jpg.glb&preload=location.glb)
|
||||
demo [here](https://yeicor-3d.github.io/yet-another-cad-viewer/?preload=logo.glb&preload=logo_hl.glb&preload=fox.glb&preload=img.jpg.glb&preload=location.glb)
|
||||
(or
|
||||
[without animation](https://yeicor-3d.github.io/yet-another-cad-viewer/?autoplay=false&preload=logo.glb&preload=fox.glb&preload=img.jpg.glb&preload=location.glb)).
|
||||
[without animation](https://yeicor-3d.github.io/yet-another-cad-viewer/?autoplay=false&preload=logo.glb&preload=logo_hl.glb&preload=fox.glb&preload=img.jpg.glb&preload=location.glb)).
|
||||
|
||||

|
||||
|
||||
## Related projects
|
||||
|
||||
- [cq-studio](https://github.com/ccazabon/cq-studio): provides an alternative workflow that detects file changes instead
|
||||
of relying on an interactive environment like Jupyter for hot-reloading.
|
||||
Uses the same backend and frontend behind the scenes.
|
||||
|
||||
@@ -3,7 +3,7 @@ https://www.npmjs.com/package/generate-license-file
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- @google/model-viewer@3.5.0
|
||||
- @google/model-viewer@4.0.0
|
||||
|
||||
This package contains the following license and notice below:
|
||||
|
||||
@@ -211,11 +211,12 @@ Apache License
|
||||
|
||||
-----------
|
||||
|
||||
The following npm package may be included in this product:
|
||||
The following npm packages may be included in this product:
|
||||
|
||||
- source-map-js@1.2.0
|
||||
- source-map-js@1.2.1
|
||||
|
||||
This package contains the following license and notice below:
|
||||
These packages each contain the following license and notice below:
|
||||
|
||||
Copyright (c) 2009-2011, Mozilla Foundation and contributors
|
||||
All rights reserved.
|
||||
@@ -979,7 +980,7 @@ third-party archives.
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- typescript@5.6.2
|
||||
- typescript@5.6.3
|
||||
|
||||
This package contains the following license and notice below:
|
||||
|
||||
@@ -1381,13 +1382,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- picocolors@1.0.1
|
||||
- picocolors@1.1.0
|
||||
|
||||
This package contains the following license and notice below:
|
||||
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2021 Alexey Raspopov, Kostiantyn Denysov, Anton Verinov
|
||||
Copyright (c) 2021-2024 Oleksii Raspopov, Kostiantyn Denysov, Anton Verinov
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -1457,7 +1458,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- three-mesh-bvh@0.7.8
|
||||
- three-mesh-bvh@0.8.2
|
||||
|
||||
This package contains the following license and notice below:
|
||||
|
||||
@@ -1691,7 +1692,7 @@ THE SOFTWARE.
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- three@0.163.0
|
||||
- three@0.169.0
|
||||
|
||||
This package contains the following license and notice below:
|
||||
|
||||
@@ -1781,7 +1782,7 @@ THE SOFTWARE.
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- vuetify@3.7.1
|
||||
- vuetify@3.7.3
|
||||
|
||||
This package contains the following license and notice below:
|
||||
|
||||
@@ -1811,16 +1812,16 @@ THE SOFTWARE.
|
||||
|
||||
The following npm packages may be included in this product:
|
||||
|
||||
- @vue/compiler-core@3.5.5
|
||||
- @vue/compiler-dom@3.5.5
|
||||
- @vue/compiler-sfc@3.5.5
|
||||
- @vue/compiler-ssr@3.5.5
|
||||
- @vue/reactivity@3.5.5
|
||||
- @vue/runtime-core@3.5.5
|
||||
- @vue/runtime-dom@3.5.5
|
||||
- @vue/server-renderer@3.5.5
|
||||
- @vue/shared@3.5.5
|
||||
- vue@3.5.5
|
||||
- @vue/compiler-core@3.5.12
|
||||
- @vue/compiler-dom@3.5.12
|
||||
- @vue/compiler-sfc@3.5.12
|
||||
- @vue/compiler-ssr@3.5.12
|
||||
- @vue/reactivity@3.5.12
|
||||
- @vue/runtime-core@3.5.12
|
||||
- @vue/runtime-dom@3.5.12
|
||||
- @vue/server-renderer@3.5.12
|
||||
- @vue/shared@3.5.12
|
||||
- vue@3.5.12
|
||||
|
||||
These packages each contain the following license and notice below:
|
||||
|
||||
@@ -1850,7 +1851,7 @@ THE SOFTWARE.
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- ktx-parse@0.7.0
|
||||
- ktx-parse@0.7.1
|
||||
|
||||
This package contains the following license and notice below:
|
||||
|
||||
@@ -1912,9 +1913,9 @@ SOFTWARE.
|
||||
|
||||
The following npm packages may be included in this product:
|
||||
|
||||
- @gltf-transform/core@4.0.8
|
||||
- @gltf-transform/extensions@4.0.8
|
||||
- @gltf-transform/functions@4.0.8
|
||||
- @gltf-transform/core@4.0.10
|
||||
- @gltf-transform/extensions@4.0.10
|
||||
- @gltf-transform/functions@4.0.10
|
||||
|
||||
These packages each contain the following license and notice below:
|
||||
|
||||
@@ -1974,7 +1975,7 @@ THE SOFTWARE.
|
||||
|
||||
The following npm package may be included in this product:
|
||||
|
||||
- postcss@8.4.45
|
||||
- postcss@8.4.47
|
||||
|
||||
This package contains the following license and notice below:
|
||||
|
||||
|
||||
@@ -36,5 +36,5 @@ Once you have the `object.glb` file, you can host it on any static file server a
|
||||
|
||||
For the example model, the build process is set up in [build.yml](../.github/workflows/build.yml), the upload process
|
||||
is set up in [deploy.yml](../.github/workflows/deploy.yml), and the final link is:
|
||||
https://yeicor-3d.github.io/yet-another-cad-viewer/?preload=example.glb
|
||||
https://yeicor-3d.github.io/yet-another-cad-viewer/?preload=example.glb&preload=example_hl.glb
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import logging
|
||||
import os
|
||||
|
||||
from build123d import * # Also works with cadquery objects!
|
||||
from build123d import Compound
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
@@ -15,9 +16,17 @@ with BuildPart() as example:
|
||||
Box(10, 10, 5)
|
||||
Cylinder(4, 5, mode=Mode.SUBTRACT)
|
||||
|
||||
# Show it in the frontend with hot-reloading
|
||||
show(example)
|
||||
# Custom colors (optional)
|
||||
example.color = (0.1, 0.3, 0.1, 1) # RGBA
|
||||
to_highlight = example.edges().group_by(Axis.Z)[-1]
|
||||
example_hl = Compound(to_highlight).translate((0, 0, 1e-3)) # To avoid z-fighting
|
||||
example_hl.color = (1, 1, .0, 1)
|
||||
|
||||
# Show it in the frontend with hot-reloading (texture and other keyword arguments are optional)
|
||||
texture = ( # MIT License Framework7 Line Icons: https://www.svgrepo.com/svg/437552/checkmark-seal
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAQAAAAB+tbP6AAAAQ0lEQVQI12P4b3+A4Z/8AYYHBw8w"
|
||||
"HHxwgOH8HyD+AsRPDjDMP+fAYD+fgcESiGfYOTCcqTnAcK4GogakFqQHpBdoBgAbGiPSbdzkhgAAAABJRU5ErkJggg==")
|
||||
show(example, example_hl, texture=texture)
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ export function hitToSelectionInfo(hit: Intersection<MObject3D>): SelectionInfo
|
||||
|
||||
function hitFaceTriangleIndices(hit: Intersection<MObject3D>): [number, number] | null {
|
||||
let faceTrianglesEnd = hit?.object?.geometry?.userData?.face_triangles_end;
|
||||
if (hit.faceIndex === undefined) return null;
|
||||
if (!hit.faceIndex) return null;
|
||||
if (!faceTrianglesEnd) { // Fallback to selecting the whole imported mesh
|
||||
//console.log("No face_triangles_end found, selecting the whole mesh");
|
||||
return [0, (hit.object.geometry.index ?? hit.object.geometry.attributes.position).count];
|
||||
|
||||
34
package.json
34
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "yet-another-cad-viewer",
|
||||
"version": "0.8.11",
|
||||
"version": "0.9.1",
|
||||
"description": "",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
@@ -15,33 +15,33 @@
|
||||
"update-licenses": "generate-license-file --input package.json --output assets/licenses.txt --overwrite"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gltf-transform/core": "^4.0.4",
|
||||
"@gltf-transform/extensions": "^4.0.8",
|
||||
"@gltf-transform/functions": "^4.0.8",
|
||||
"@google/model-viewer": "^3.5.0",
|
||||
"@gltf-transform/core": "^4.1.0",
|
||||
"@gltf-transform/extensions": "^4.1.0",
|
||||
"@gltf-transform/functions": "^4.1.0",
|
||||
"@google/model-viewer": "^4.0.0",
|
||||
"@jamescoyle/vue-icon": "^0.1.2",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@mdi/svg": "^7.4.47",
|
||||
"three": "^0.163.0",
|
||||
"three-mesh-bvh": "^0.8.0",
|
||||
"three": "^0.169.0",
|
||||
"three-mesh-bvh": "^0.8.2",
|
||||
"three-orientation-gizmo": "https://github.com/jrj2211/three-orientation-gizmo",
|
||||
"vue": "^3.5.7",
|
||||
"vuetify": "^3.7.2"
|
||||
"vue": "^3.5.12",
|
||||
"vuetify": "^3.7.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/three": "^0.163.0",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/three": "^0.169.0",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"@vitejs/plugin-vue-jsx": "^4.0.1",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"buffer": "^5.5.0||^6.0.0",
|
||||
"commander": "^12.0.0",
|
||||
"generate-license-file": "^3.5.1",
|
||||
"npm-run-all2": "^6.2.3",
|
||||
"terser": "^5.33.0",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^5.4.7",
|
||||
"vue-tsc": "^2.1.6"
|
||||
"generate-license-file": "^3.6.0",
|
||||
"npm-run-all2": "^7.0.1",
|
||||
"terser": "^5.36.0",
|
||||
"typescript": "~5.6.3",
|
||||
"vite": "^5.4.10",
|
||||
"vue-tsc": "^2.1.10"
|
||||
}
|
||||
}
|
||||
|
||||
163
poetry.lock
generated
163
poetry.lock
generated
@@ -487,95 +487,90 @@ ptyprocess = ">=0.5"
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "10.4.0"
|
||||
version = "11.0.0"
|
||||
description = "Python Imaging Library (Fork)"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"},
|
||||
{file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"},
|
||||
{file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"},
|
||||
{file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"},
|
||||
{file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"},
|
||||
{file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"},
|
||||
{file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"},
|
||||
{file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"},
|
||||
{file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"},
|
||||
{file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"},
|
||||
{file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"},
|
||||
{file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"},
|
||||
{file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"},
|
||||
{file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"},
|
||||
{file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"},
|
||||
{file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"},
|
||||
{file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"},
|
||||
{file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"},
|
||||
{file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"},
|
||||
{file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"},
|
||||
{file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"},
|
||||
{file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"},
|
||||
{file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291"},
|
||||
{file = "pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"},
|
||||
{file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de"},
|
||||
{file = "pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84"},
|
||||
{file = "pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b"},
|
||||
{file = "pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003"},
|
||||
{file = "pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2"},
|
||||
{file = "pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a"},
|
||||
{file = "pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8"},
|
||||
{file = "pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8"},
|
||||
{file = "pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904"},
|
||||
{file = "pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-win32.whl", hash = "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd"},
|
||||
{file = "pillow-11.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd"},
|
||||
{file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"},
|
||||
{file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"},
|
||||
{file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"},
|
||||
{file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"},
|
||||
{file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"},
|
||||
{file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"},
|
||||
{file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"},
|
||||
{file = "pillow-11.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06"},
|
||||
{file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273"},
|
||||
{file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790"},
|
||||
{file = "pillow-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944"},
|
||||
{file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
|
||||
docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
|
||||
fpx = ["olefile"]
|
||||
mic = ["olefile"]
|
||||
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
|
||||
@@ -929,4 +924,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "c7ab4daa707db1d54f8af490ab8f85a5d80052049aead04b08c867739829418d"
|
||||
content-hash = "b4dfaa40848685a491aa10c1a4332eb89d081f711ef8e35c9b6a0e68256c39ed"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "yacv-server"
|
||||
version = "0.8.11"
|
||||
version = "0.9.1"
|
||||
description = "Yet Another CAD Viewer (server)"
|
||||
authors = ["Yeicor <4929005+Yeicor@users.noreply.github.com>"]
|
||||
license = "MIT"
|
||||
@@ -18,7 +18,7 @@ build123d = ">=0.5,<0.8"
|
||||
|
||||
# Misc
|
||||
pygltflib = "^1.16.2"
|
||||
pillow = "^10.2.0"
|
||||
pillow = ">=10.2,<12.0"
|
||||
|
||||
[tool.poetry.build]
|
||||
generate-setup-file = false
|
||||
|
||||
@@ -10,12 +10,30 @@ from OCP.TopExp import TopExp
|
||||
from OCP.TopLoc import TopLoc_Location
|
||||
from OCP.TopTools import TopTools_IndexedMapOfShape
|
||||
from OCP.TopoDS import TopoDS_Shape
|
||||
from build123d import Compound, Shape
|
||||
from build123d import Compound, Shape, Color
|
||||
|
||||
from yacv_server.gltf import GLTFMgr
|
||||
|
||||
CADCoreLike = Union[TopoDS_Shape, TopLoc_Location] # Faces, Edges, Vertices and Locations for now
|
||||
CADLike = Union[CADCoreLike, any] # build123d and cadquery types
|
||||
ColorTuple = Tuple[float, float, float, float]
|
||||
|
||||
|
||||
def get_color(obj: any) -> Optional[ColorTuple]:
|
||||
"""Get color from a CAD Object or any other color-like object"""
|
||||
if 'color' in dir(obj):
|
||||
obj = obj.color
|
||||
if isinstance(obj, tuple):
|
||||
c = None
|
||||
if len(obj) == 3:
|
||||
c = obj + (1,)
|
||||
elif len(obj) == 4:
|
||||
c = obj
|
||||
# noinspection PyTypeChecker
|
||||
return [min(max(float(x), 0), 1) for x in c]
|
||||
if isinstance(obj, Color):
|
||||
return obj.to_tuple()
|
||||
return None
|
||||
|
||||
|
||||
def get_shape(obj: CADLike, error: bool = True) -> Optional[CADCoreLike]:
|
||||
|
||||
@@ -8,6 +8,12 @@ _checkerboard_image_bytes = base64.decodebytes(
|
||||
b'iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAF0lEQVQI12N49OjR////Gf'
|
||||
b'/////48WMATwULS8tcyj8AAAAASUVORK5CYII=')
|
||||
|
||||
def get_version() -> str:
|
||||
try:
|
||||
return importlib.metadata.version("yacv_server")
|
||||
except importlib.metadata.PackageNotFoundError:
|
||||
return "unknown"
|
||||
|
||||
|
||||
class GLTFMgr:
|
||||
"""A utility class to build our GLTF2 objects easily and incrementally"""
|
||||
@@ -32,7 +38,7 @@ class GLTFMgr:
|
||||
|
||||
def __init__(self, image: Optional[Tuple[bytes, str]] = (_checkerboard_image_bytes, 'image/png')):
|
||||
self.gltf = GLTF2(
|
||||
asset=Asset(generator=f"yacv_server@{importlib.metadata.version('yacv_server')}"),
|
||||
asset=Asset(generator=f"yacv_server@{get_version()}"),
|
||||
scene=0,
|
||||
scenes=[Scene(nodes=[0])],
|
||||
nodes=[Node(mesh=0)], # TODO: Server-side detection of shallow copies --> nodes
|
||||
@@ -71,9 +77,9 @@ class GLTFMgr:
|
||||
return [p for p in self.gltf.meshes[0].primitives if p.mode == POINTS][0]
|
||||
|
||||
def add_face(self, vertices_raw: List[Vector], indices_raw: List[Tuple[int, int, int]],
|
||||
tex_coord_raw: List[Tuple[float, float]],
|
||||
color: Tuple[float, float, float, float] = (1.0, 0.75, 0.0, 1.0)):
|
||||
tex_coord_raw: List[Tuple[float, float]], color: Optional[Tuple[float, float, float, float]] = None):
|
||||
"""Add a face to the GLTF mesh"""
|
||||
if color is None: color = (1.0, 0.75, 0.0, 1.0)
|
||||
# assert len(vertices_raw) == len(tex_coord_raw), f"Vertices and texture coordinates have different lengths"
|
||||
# assert min([i for t in indices_raw for i in t]) == 0, f"Face indices start at {min(indices_raw)}"
|
||||
# assert max([e for t in indices_raw for e in t]) < len(vertices_raw), f"Indices have non-existing vertices"
|
||||
@@ -85,8 +91,9 @@ class GLTFMgr:
|
||||
self._faces_primitive.extras["face_triangles_end"].append(len(self.face_indices))
|
||||
|
||||
def add_edge(self, vertices_raw: List[Tuple[Tuple[float, float, float], Tuple[float, float, float]]],
|
||||
color: Tuple[float, float, float, float] = (0.1, 0.1, 1.0, 1.0)):
|
||||
color: Optional[Tuple[float, float, float, float]] = None):
|
||||
"""Add an edge to the GLTF mesh"""
|
||||
if color is None: color = (0.1, 0.1, 1.0, 1.0)
|
||||
vertices_flat = [v for t in vertices_raw for v in t] # Line from 0 to 1, 2 to 3, 4 to 5, etc.
|
||||
base_index = len(self.edge_positions) // 3
|
||||
self.edge_indices.extend([base_index + i for i in range(len(vertices_flat))])
|
||||
@@ -94,9 +101,9 @@ class GLTFMgr:
|
||||
self.edge_colors.extend([col for _ in range(len(vertices_flat)) for col in color])
|
||||
self._edges_primitive.extras["edge_points_end"].append(len(self.edge_indices))
|
||||
|
||||
def add_vertex(self, vertex: Tuple[float, float, float],
|
||||
color: Tuple[float, float, float, float] = (0.1, 0.1, 0.1, 1.0)):
|
||||
def add_vertex(self, vertex: Tuple[float, float, float], color: Optional[Tuple[float, float, float, float]] = None):
|
||||
"""Add a vertex to the GLTF mesh"""
|
||||
if color is None: color = (0.1, 0.1, 0.1, 1.0)
|
||||
base_index = len(self.vertex_positions) // 3
|
||||
self.vertex_indices.append(base_index)
|
||||
self.vertex_positions.extend(vertex)
|
||||
|
||||
@@ -16,18 +16,24 @@ def build_logo(text: bool = True) -> Dict[str, Union[Part, Location, str]]:
|
||||
text_at_plane = Plane.YZ
|
||||
text_at_plane.origin = faces().group_by(Axis.X)[-1].face().center()
|
||||
with BuildSketch(text_at_plane.location):
|
||||
Text('Yet Another\nCAD Viewer', 7, font_path='/usr/share/fonts/TTF/OpenSans-Regular.ttf')
|
||||
Text('Yet Another\nCAD Viewer', 6, font_path='/usr/share/fonts/TTF/Hack-Regular.ttf')
|
||||
extrude(amount=1)
|
||||
|
||||
# Highlight text edges with a custom color
|
||||
to_highlight = logo_obj.edges().group_by(Axis.X)[-1]
|
||||
logo_obj_hl = Compound(to_highlight).translate((1e-3, 0, 0)) # To avoid z-fighting
|
||||
logo_obj_hl.color = (0, 0.3, 0.3, 1)
|
||||
|
||||
# Add a logo image to the CAD part
|
||||
logo_img_location = logo_obj.faces().group_by(Axis.X)[0].face().center_location
|
||||
logo_img_location *= Location((0, 0, 4e-2), (0, 0, 90)) # Avoid overlapping and adjust placement
|
||||
|
||||
logo_img_path = os.path.join(ASSETS_DIR, 'img.jpg')
|
||||
img_glb_bytes, img_name = image_to_gltf(logo_img_path, logo_img_location, height=18)
|
||||
|
||||
# Add an animated fox to the CAD part
|
||||
fox_glb_bytes = open(os.path.join(ASSETS_DIR, 'fox.glb'), 'rb').read()
|
||||
|
||||
return {'fox': fox_glb_bytes, 'logo': logo_obj, 'location': logo_img_location, img_name: img_glb_bytes}
|
||||
return {'fox': fox_glb_bytes, 'logo': logo_obj, 'logo_hl': logo_obj_hl, 'location': logo_img_location, img_name: img_glb_bytes}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List, Dict, Tuple
|
||||
from typing import List, Dict, Tuple, Optional
|
||||
|
||||
from OCP.BRep import BRep_Tool
|
||||
from OCP.BRepAdaptor import BRepAdaptor_Curve
|
||||
@@ -8,7 +8,7 @@ from OCP.TopoDS import TopoDS_Face, TopoDS_Edge, TopoDS_Shape, TopoDS_Vertex
|
||||
from build123d import Shape, Vertex, Face, Location
|
||||
from pygltflib import GLTF2
|
||||
|
||||
from yacv_server.cad import CADCoreLike
|
||||
from yacv_server.cad import CADCoreLike, ColorTuple
|
||||
from yacv_server.gltf import GLTFMgr
|
||||
from yacv_server.mylogger import logger
|
||||
|
||||
@@ -20,9 +20,14 @@ def tessellate(
|
||||
faces: bool = True,
|
||||
edges: bool = True,
|
||||
vertices: bool = True,
|
||||
obj_color: Optional[ColorTuple] = None,
|
||||
texture: Optional[Tuple[bytes, str]] = None,
|
||||
) -> GLTF2:
|
||||
"""Tessellate a whole shape into a list of triangle vertices and a list of triangle indices."""
|
||||
mgr = GLTFMgr()
|
||||
if texture is None:
|
||||
mgr = GLTFMgr()
|
||||
else:
|
||||
mgr = GLTFMgr(texture)
|
||||
|
||||
if isinstance(cad_like, TopLoc_Location):
|
||||
mgr.add_location(Location(cad_like))
|
||||
@@ -34,21 +39,25 @@ def tessellate(
|
||||
edge_to_faces: Dict[str, List[TopoDS_Face]] = {}
|
||||
vertex_to_faces: Dict[str, List[TopoDS_Face]] = {}
|
||||
if faces:
|
||||
for face in shape.faces():
|
||||
_tessellate_face(mgr, face.wrapped, tolerance, angular_tolerance)
|
||||
shape_faces = shape.faces()
|
||||
for face in shape_faces:
|
||||
_tessellate_face(mgr, face.wrapped, tolerance, angular_tolerance, obj_color)
|
||||
if edges:
|
||||
for edge in face.edges():
|
||||
edge_to_faces[edge.wrapped] = edge_to_faces.get(edge.wrapped, []) + [face.wrapped]
|
||||
if vertices:
|
||||
for vertex in face.vertices():
|
||||
vertex_to_faces[vertex.wrapped] = vertex_to_faces.get(vertex.wrapped, []) + [face.wrapped]
|
||||
if len(shape_faces) > 0: obj_color = None # Don't color edges/vertices if faces are colored
|
||||
if edges:
|
||||
for edge in shape.edges():
|
||||
shape_edges = shape.edges()
|
||||
for edge in shape_edges:
|
||||
_tessellate_edge(mgr, edge.wrapped, edge_to_faces.get(edge.wrapped, []), angular_tolerance,
|
||||
angular_tolerance)
|
||||
angular_tolerance, obj_color)
|
||||
if len(shape_edges) > 0: obj_color = None # Don't color vertices if edges are colored
|
||||
if vertices:
|
||||
for vertex in shape.vertices():
|
||||
_tessellate_vertex(mgr, vertex.wrapped, vertex_to_faces.get(vertex.wrapped, []))
|
||||
_tessellate_vertex(mgr, vertex.wrapped, vertex_to_faces.get(vertex.wrapped, []), obj_color)
|
||||
|
||||
return mgr.build()
|
||||
|
||||
@@ -57,7 +66,8 @@ def _tessellate_face(
|
||||
mgr: GLTFMgr,
|
||||
ocp_face: TopoDS_Face,
|
||||
tolerance: float = 1e-3,
|
||||
angular_tolerance: float = 0.1
|
||||
angular_tolerance: float = 0.1,
|
||||
color: Optional[ColorTuple] = None,
|
||||
):
|
||||
face = Shape(ocp_face)
|
||||
# face.mesh(tolerance, angular_tolerance)
|
||||
@@ -75,7 +85,7 @@ def _tessellate_face(
|
||||
|
||||
vertices = tri_mesh[0]
|
||||
indices = tri_mesh[1]
|
||||
mgr.add_face(vertices, indices, uv)
|
||||
mgr.add_face(vertices, indices, uv, color)
|
||||
|
||||
|
||||
def _push_point(v: Tuple[float, float, float], faces: List[TopoDS_Face]) -> Tuple[float, float, float]:
|
||||
@@ -100,6 +110,7 @@ def _tessellate_edge(
|
||||
faces: List[TopoDS_Face],
|
||||
angular_deflection: float = 0.1,
|
||||
curvature_deflection: float = 0.1,
|
||||
color: Optional[ColorTuple] = None,
|
||||
):
|
||||
# Use a curve discretizer to get the vertices
|
||||
curve = BRepAdaptor_Curve(ocp_edge)
|
||||
@@ -117,11 +128,12 @@ def _tessellate_edge(
|
||||
|
||||
# Convert strip of vertices to a list of pairs of vertices
|
||||
vertices = [(vertices[i], vertices[i + 1]) for i in range(len(vertices) - 1)]
|
||||
mgr.add_edge(vertices)
|
||||
mgr.add_edge(vertices, color)
|
||||
|
||||
|
||||
def _tessellate_vertex(mgr: GLTFMgr, ocp_vertex: TopoDS_Vertex, faces: List[TopoDS_Face]):
|
||||
def _tessellate_vertex(mgr: GLTFMgr, ocp_vertex: TopoDS_Vertex, faces: List[TopoDS_Face],
|
||||
color: Optional[ColorTuple] = None):
|
||||
c = Vertex(ocp_vertex).center()
|
||||
mgr.add_vertex(_push_point((c.X, c.Y, c.Z), faces))
|
||||
mgr.add_vertex(_push_point((c.X, c.Y, c.Z), faces), color)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import atexit
|
||||
import base64
|
||||
import copy
|
||||
import inspect
|
||||
import os
|
||||
@@ -8,23 +9,25 @@ import threading
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from http.server import ThreadingHTTPServer
|
||||
from importlib.metadata import version
|
||||
from threading import Thread
|
||||
from typing import Optional, Dict, Union, Callable, List, Tuple
|
||||
|
||||
from OCP.TopLoc import TopLoc_Location
|
||||
from OCP.TopoDS import TopoDS_Shape
|
||||
# noinspection PyProtectedMember
|
||||
from build123d import Shape, Axis, Location, Vector
|
||||
from build123d import Shape, Axis, Location, Vector, Color
|
||||
from dataclasses_json import dataclass_json
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
|
||||
from yacv_server.cad import _hashcode, ColorTuple, get_color
|
||||
from yacv_server.cad import get_shape, grab_all_cad, CADCoreLike, CADLike
|
||||
from yacv_server.gltf import get_version
|
||||
from yacv_server.myhttp import HTTPHandler
|
||||
from yacv_server.mylogger import logger
|
||||
from yacv_server.pubsub import BufferedPubSub
|
||||
from yacv_server.rwlock import RWLock
|
||||
from yacv_server.tessellate import tessellate
|
||||
from yacv_server.cad import _hashcode
|
||||
|
||||
|
||||
@dataclass_json
|
||||
@@ -44,7 +47,7 @@ YACVSupported = Union[bytes, CADCoreLike]
|
||||
|
||||
class UpdatesApiFullData(UpdatesApiData):
|
||||
obj: YACVSupported
|
||||
"""The OCCT object, if any (not serialized)"""
|
||||
"""The OCCT object (not serialized)"""
|
||||
kwargs: Optional[Dict[str, any]]
|
||||
"""The show_object options, if any (not serialized)"""
|
||||
|
||||
@@ -88,6 +91,14 @@ class YACV:
|
||||
frontend_lock: RWLock
|
||||
"""Lock to ensure that the frontend has finished working before we shut down"""
|
||||
|
||||
texture: Optional[Tuple[bytes, str]]
|
||||
"""Default texture to use for model faces, in (data, mimetype) format.
|
||||
If left as None, a default checkerboard texture will be used.
|
||||
|
||||
It can be set with the YACV_BASE_TEXTURE=<uri> and overriden by `show(..., texture="<uri>")`.
|
||||
The <uri> can be file:<path> or data:<mime>;base64,<data> where <mime> is the mime type and
|
||||
<data> is the base64 encoded image."""
|
||||
|
||||
def __init__(self):
|
||||
self.server_thread = None
|
||||
self.server = None
|
||||
@@ -98,7 +109,8 @@ class YACV:
|
||||
self.at_least_one_client = threading.Event()
|
||||
self.shutting_down = threading.Event()
|
||||
self.frontend_lock = RWLock()
|
||||
logger.info('Using yacv-server v%s', version('yacv-server'))
|
||||
self.texture = _read_texture_uri(os.getenv("YACV_BASE_TEXTURE"))
|
||||
logger.info('Using yacv-server v%s', get_version())
|
||||
|
||||
def start(self):
|
||||
"""Starts the web server in the background"""
|
||||
@@ -165,12 +177,32 @@ class YACV:
|
||||
self.server.serve_forever()
|
||||
|
||||
def show(self, *objs: List[YACVSupported], names: Optional[Union[str, List[str]]] = None, **kwargs):
|
||||
"""
|
||||
Shows the given CAD objects in the frontend. The objects will be tessellated and converted to GLTF. Optionally,
|
||||
the following keyword arguments can be used:
|
||||
|
||||
- auto_clear: Whether to clear the previous objects before showing the new ones (default: True)
|
||||
- texture: The texture to use for the faces of the object (see `YACV.texture` for more info)
|
||||
- color: The default color to use for the objects (can be overridden by the `color` attribute of each object)
|
||||
- tolerance: The tolerance for tessellating the object (default: 0.1)
|
||||
- angular_tolerance: The angular tolerance for tessellating the object (default: 0.1)
|
||||
- faces: Whether to tessellate and show the faces of the object (default: True)
|
||||
- edges: Whether to tessellate and show the edges of the object (default: True)
|
||||
- vertices: Whether to tessellate and show the vertices of the object (default: True)
|
||||
|
||||
:param objs: The CAD objects to show. Can be CAD-like objects (solids, locations, etc.) or bytes (GLTF) objects.
|
||||
:param names: The names of the objects. If None, the variable names will be used (if possible). The number of
|
||||
names must match the number of objects. An object of the same name will be replaced in the frontend.
|
||||
:param kwargs: Additional options for the show_object event.
|
||||
"""
|
||||
# Prepare the arguments
|
||||
start = time.time()
|
||||
names = names or [_find_var_name(obj) for obj in objs]
|
||||
if isinstance(names, str):
|
||||
names = [names]
|
||||
assert len(names) == len(objs), 'Number of names must match the number of objects'
|
||||
if 'color' in kwargs:
|
||||
kwargs['color'] = get_color(kwargs['color'])
|
||||
|
||||
# Handle auto clearing of previous objects
|
||||
if kwargs.get('auto_clear', True):
|
||||
@@ -185,6 +217,10 @@ class YACV:
|
||||
|
||||
# Publish the show event
|
||||
for obj, name in zip(objs, names):
|
||||
obj_color = get_color(obj)
|
||||
if obj_color is not None:
|
||||
kwargs = kwargs.copy()
|
||||
kwargs['color'] = obj_color
|
||||
if not isinstance(obj, bytes):
|
||||
obj = _preprocess_cad(obj, **kwargs)
|
||||
_hash = _hashcode(obj, **kwargs)
|
||||
@@ -194,7 +230,7 @@ class YACV:
|
||||
logger.info('show %s took %.3f seconds', names, time.time() - start)
|
||||
|
||||
def show_cad_all(self, **kwargs):
|
||||
"""Publishes all CAD objects in the current scope to the server"""
|
||||
"""Publishes all CAD objects in the current scope to the server. See `show` for more details."""
|
||||
all_cad = list(grab_all_cad()) # List for reproducible iteration order
|
||||
self.show(*[cad for _, cad in all_cad], names=[name for name, _ in all_cad], **kwargs)
|
||||
|
||||
@@ -273,11 +309,17 @@ class YACV:
|
||||
if isinstance(event.obj, bytes): # Already a GLTF
|
||||
publish_to.publish(event.obj)
|
||||
else: # CAD object to tessellate and convert to GLTF
|
||||
texture_override_uri = event.kwargs.get('texture', None)
|
||||
texture_override = None
|
||||
if isinstance(texture_override_uri, str):
|
||||
texture_override = _read_texture_uri(texture_override_uri)
|
||||
gltf = tessellate(event.obj, tolerance=event.kwargs.get('tolerance', 0.1),
|
||||
angular_tolerance=event.kwargs.get('angular_tolerance', 0.1),
|
||||
faces=event.kwargs.get('faces', True),
|
||||
edges=event.kwargs.get('edges', True),
|
||||
vertices=event.kwargs.get('vertices', True))
|
||||
vertices=event.kwargs.get('vertices', True),
|
||||
obj_color=event.kwargs.get('color', None),
|
||||
texture=texture_override or self.texture)
|
||||
glb_list_of_bytes = gltf.save_to_bytes()
|
||||
glb_bytes = b''.join(glb_list_of_bytes)
|
||||
publish_to.publish(glb_bytes)
|
||||
@@ -301,6 +343,25 @@ class YACV:
|
||||
f.write(self.export(name)[0])
|
||||
|
||||
|
||||
def _read_texture_uri(uri: str) -> Optional[Tuple[bytes, str]]:
|
||||
if uri is None:
|
||||
return None
|
||||
if uri.startswith("file:"):
|
||||
path = uri[len("file:"):]
|
||||
with open(path, 'rb') as f:
|
||||
data = f.read()
|
||||
buf = BytesIO(data)
|
||||
img = Image.open(buf)
|
||||
mtype = img.get_format_mimetype()
|
||||
return data, mtype
|
||||
if uri.startswith("data:"): # https://en.wikipedia.org/wiki/Data_URI_scheme#Syntax (limited)
|
||||
mtype_and_data = uri[len("data:"):]
|
||||
mtype = mtype_and_data.split(";", 1)[0]
|
||||
data_str = mtype_and_data.split(",", 1)[1]
|
||||
data = base64.b64decode(data_str)
|
||||
return data, mtype
|
||||
return None
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
def _preprocess_cad(obj: CADLike, **kwargs) -> CADCoreLike:
|
||||
# Get the shape of a CAD-like object
|
||||
|
||||
Reference in New Issue
Block a user