poppygl 0.0.21 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -2
- package/dist/index.js +128 -50
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -204,8 +204,10 @@ declare function renderGLTFToPNGBufferFromURL(url: string, options?: RenderGLTFT
|
|
|
204
204
|
type RenderGLTFToPNGBufferFromGLBBufferOptions = RenderOptionsInput;
|
|
205
205
|
declare function renderGLTFToPNGBufferFromGLBBuffer(glb: ArrayBuffer | Uint8Array, options?: RenderGLTFToPNGBufferFromGLBBufferOptions): Promise<Buffer>;
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
interface RenderGLTFToPNGBufferOptions extends RenderOptionsInput, LoadGLTFWithResourcesFromURLOptions {
|
|
208
|
+
}
|
|
209
|
+
declare function renderGLTFToPNGBuffer(gltfOrJson: string | any, options?: RenderGLTFToPNGBufferOptions, resources?: GLTFResources): Promise<Buffer>;
|
|
208
210
|
|
|
209
211
|
declare function renderSceneFromGLTF(scene: GLTFScene, options?: RenderOptionsInput, imageFactory?: ImageFactory): RenderResult;
|
|
210
212
|
|
|
211
|
-
export { type BitmapLike, type Camera, type CameraRotation, type CameraUp, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, type DebugPoint, type DrawCall, type FetchLike, type GLTFResources, type GLTFScene, type GridOptions, type ImageFactory, type LightSettings, type LoadGLTFWithResourcesFromURLOptions, type Material, type MutableRGBA, type RGBA, type RenderGLTFToPNGBufferFromGLBBufferOptions, type RenderGLTFToPNGBufferFromURLOptions, type RenderOptions, type RenderOptionsInput, type RenderResult, SoftwareRenderer, bufferFromDataURI, buildCamera, computeSmoothNormals, computeWorldAABB, createGrid, createInfiniteGrid, createSceneFromGLTF, createUint8Bitmap, decodeImageFromBuffer, drawInfiniteGrid, encodePNGToBuffer, getDefaultRenderOptions, hexToRgb, isJPG, isPNG, loadGLTFWithResourcesFromURL, pureImageFactory, renderDrawCalls, renderGLTFToPNGBuffer, renderGLTFToPNGBufferFromGLBBuffer, renderGLTFToPNGBufferFromURL, renderSceneFromGLTF, resolveRenderOptions };
|
|
213
|
+
export { type BitmapLike, type Camera, type CameraRotation, type CameraUp, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, type DebugPoint, type DrawCall, type FetchLike, type GLTFResources, type GLTFScene, type GridOptions, type ImageFactory, type LightSettings, type LoadGLTFWithResourcesFromURLOptions, type Material, type MutableRGBA, type RGBA, type RenderGLTFToPNGBufferFromGLBBufferOptions, type RenderGLTFToPNGBufferFromURLOptions, type RenderGLTFToPNGBufferOptions, type RenderOptions, type RenderOptionsInput, type RenderResult, SoftwareRenderer, bufferFromDataURI, buildCamera, computeSmoothNormals, computeWorldAABB, createGrid, createInfiniteGrid, createSceneFromGLTF, createUint8Bitmap, decodeImageFromBuffer, drawInfiniteGrid, encodePNGToBuffer, getDefaultRenderOptions, hexToRgb, isJPG, isPNG, loadGLTFWithResourcesFromURL, pureImageFactory, renderDrawCalls, renderGLTFToPNGBuffer, renderGLTFToPNGBufferFromGLBBuffer, renderGLTFToPNGBufferFromURL, renderSceneFromGLTF, resolveRenderOptions };
|
package/dist/index.js
CHANGED
|
@@ -1612,10 +1612,50 @@ function createSceneFromGLTF(gltf, resources) {
|
|
|
1612
1612
|
// lib/gltf/resourceUtils.ts
|
|
1613
1613
|
import { PassThrough } from "readable-stream";
|
|
1614
1614
|
import * as PImage from "pureimage";
|
|
1615
|
+
|
|
1616
|
+
// lib/utils/bytes.ts
|
|
1617
|
+
function getNodeBuffer() {
|
|
1618
|
+
const maybeBuffer = globalThis.Buffer;
|
|
1619
|
+
if (!maybeBuffer) {
|
|
1620
|
+
throw new Error("Node Buffer API is not available in this runtime.");
|
|
1621
|
+
}
|
|
1622
|
+
return maybeBuffer;
|
|
1623
|
+
}
|
|
1624
|
+
function toUint8Array(chunk) {
|
|
1625
|
+
if (chunk instanceof Uint8Array) return chunk;
|
|
1626
|
+
if (chunk instanceof ArrayBuffer) return new Uint8Array(chunk);
|
|
1627
|
+
return new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
1628
|
+
}
|
|
1629
|
+
function concatUint8Arrays(chunks) {
|
|
1630
|
+
const totalLength = chunks.reduce((length, chunk) => length + chunk.length, 0);
|
|
1631
|
+
const result = new Uint8Array(totalLength);
|
|
1632
|
+
let offset = 0;
|
|
1633
|
+
for (const chunk of chunks) {
|
|
1634
|
+
result.set(chunk, offset);
|
|
1635
|
+
offset += chunk.length;
|
|
1636
|
+
}
|
|
1637
|
+
return result;
|
|
1638
|
+
}
|
|
1639
|
+
function base64ToUint8Array(base64) {
|
|
1640
|
+
if (typeof globalThis.atob === "function") {
|
|
1641
|
+
const binary = globalThis.atob(base64);
|
|
1642
|
+
const bytes = new Uint8Array(binary.length);
|
|
1643
|
+
for (let i = 0; i < binary.length; i++) {
|
|
1644
|
+
bytes[i] = binary.charCodeAt(i);
|
|
1645
|
+
}
|
|
1646
|
+
return bytes;
|
|
1647
|
+
}
|
|
1648
|
+
return new Uint8Array(getNodeBuffer().from(base64, "base64"));
|
|
1649
|
+
}
|
|
1650
|
+
function uint8ArrayToNodeBuffer(bytes) {
|
|
1651
|
+
return getNodeBuffer().from(bytes);
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// lib/gltf/resourceUtils.ts
|
|
1615
1655
|
function bufferFromDataURI(uri) {
|
|
1616
1656
|
const match = uri.match(/^data:.*?;base64,(.*)$/);
|
|
1617
1657
|
if (!match) throw new Error(`Unsupported data URI: ${uri.slice(0, 64)}...`);
|
|
1618
|
-
return
|
|
1658
|
+
return base64ToUint8Array(match[1]);
|
|
1619
1659
|
}
|
|
1620
1660
|
function isPNG(filenameOrUri) {
|
|
1621
1661
|
return /\.png(\?|$)/i.test(filenameOrUri) || /image\/png/i.test(filenameOrUri);
|
|
@@ -1632,7 +1672,7 @@ function detectMimeTypeFromBuffer(buf, hint) {
|
|
|
1632
1672
|
}
|
|
1633
1673
|
function bufferToStream(buf) {
|
|
1634
1674
|
const stream = new PassThrough();
|
|
1635
|
-
stream.end(
|
|
1675
|
+
stream.end(buf);
|
|
1636
1676
|
return stream;
|
|
1637
1677
|
}
|
|
1638
1678
|
async function decodeImageFromBuffer(buf, mimeType) {
|
|
@@ -1808,11 +1848,16 @@ import * as PImage3 from "pureimage";
|
|
|
1808
1848
|
async function encodePNGToBuffer(image) {
|
|
1809
1849
|
const passThrough = new PassThrough2();
|
|
1810
1850
|
const chunks = [];
|
|
1811
|
-
passThrough.on(
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1851
|
+
passThrough.on(
|
|
1852
|
+
"data",
|
|
1853
|
+
(chunk) => {
|
|
1854
|
+
chunks.push(toUint8Array(chunk));
|
|
1855
|
+
}
|
|
1856
|
+
);
|
|
1857
|
+
const resultPromise = new Promise((resolve, reject) => {
|
|
1858
|
+
passThrough.on("end", () => {
|
|
1859
|
+
resolve(uint8ArrayToNodeBuffer(concatUint8Arrays(chunks)));
|
|
1860
|
+
});
|
|
1816
1861
|
passThrough.on("error", reject);
|
|
1817
1862
|
});
|
|
1818
1863
|
await PImage3.encodePNGToStream(image, passThrough);
|
|
@@ -1908,62 +1953,59 @@ async function renderGLTFToPNGBufferFromGLBBuffer(glb, options = {}) {
|
|
|
1908
1953
|
return encodePNGToBuffer(bitmap);
|
|
1909
1954
|
}
|
|
1910
1955
|
|
|
1911
|
-
//
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1956
|
+
// lib/gltf/loadGLTFWithResourcesFromPath.ts
|
|
1957
|
+
async function loadGLTFWithResourcesFromPath(gltfPath) {
|
|
1958
|
+
const fs = await import("fs/promises");
|
|
1959
|
+
const path = await import("path");
|
|
1915
1960
|
const baseDir = path.dirname(gltfPath);
|
|
1916
|
-
const gltf = JSON.parse(await fs.
|
|
1961
|
+
const gltf = JSON.parse(await fs.readFile(gltfPath, "utf8"));
|
|
1917
1962
|
const buffers = await Promise.all(
|
|
1918
|
-
(gltf.buffers || []).map(async (
|
|
1919
|
-
if (
|
|
1920
|
-
return bufferFromDataURI(
|
|
1963
|
+
(gltf.buffers || []).map(async (buffer) => {
|
|
1964
|
+
if (buffer.uri?.startsWith("data:")) {
|
|
1965
|
+
return bufferFromDataURI(buffer.uri);
|
|
1921
1966
|
}
|
|
1922
|
-
if (
|
|
1923
|
-
const resolved = path.resolve(baseDir, decodeURIComponent(
|
|
1924
|
-
return fs.
|
|
1967
|
+
if (buffer.uri) {
|
|
1968
|
+
const resolved = path.resolve(baseDir, decodeURIComponent(buffer.uri));
|
|
1969
|
+
return fs.readFile(resolved);
|
|
1925
1970
|
}
|
|
1926
1971
|
throw new Error("Buffer without uri not supported in this loader.");
|
|
1927
1972
|
})
|
|
1928
1973
|
);
|
|
1929
1974
|
const images = await Promise.all(
|
|
1930
|
-
(gltf.images || []).map(async (
|
|
1931
|
-
if (
|
|
1932
|
-
if (
|
|
1933
|
-
const
|
|
1934
|
-
return decodeImageFromBuffer(
|
|
1975
|
+
(gltf.images || []).map(async (image) => {
|
|
1976
|
+
if (image.uri) {
|
|
1977
|
+
if (image.uri.startsWith("data:")) {
|
|
1978
|
+
const bytes = bufferFromDataURI(image.uri);
|
|
1979
|
+
return decodeImageFromBuffer(bytes, image.mimeType);
|
|
1935
1980
|
}
|
|
1936
|
-
const filePath = path.resolve(baseDir, decodeURIComponent(
|
|
1937
|
-
const
|
|
1938
|
-
const hintedMime = isPNG(
|
|
1939
|
-
return decodeImageFromBuffer(
|
|
1981
|
+
const filePath = path.resolve(baseDir, decodeURIComponent(image.uri));
|
|
1982
|
+
const fileBytes = await fs.readFile(filePath);
|
|
1983
|
+
const hintedMime = isPNG(image.uri) ? "image/png" : isJPG(image.uri) ? "image/jpeg" : image.mimeType;
|
|
1984
|
+
return decodeImageFromBuffer(fileBytes, hintedMime);
|
|
1940
1985
|
}
|
|
1941
|
-
if (typeof
|
|
1942
|
-
const bufferView = gltf.bufferViews?.[
|
|
1986
|
+
if (typeof image.bufferView === "number") {
|
|
1987
|
+
const bufferView = gltf.bufferViews?.[image.bufferView];
|
|
1943
1988
|
if (!bufferView) {
|
|
1944
|
-
throw new Error(`Invalid image bufferView index ${
|
|
1989
|
+
throw new Error(`Invalid image bufferView index ${image.bufferView}`);
|
|
1945
1990
|
}
|
|
1946
1991
|
const buffer = buffers[bufferView.buffer];
|
|
1947
|
-
if (!buffer)
|
|
1992
|
+
if (!buffer) {
|
|
1948
1993
|
throw new Error(
|
|
1949
|
-
`Missing buffer for image bufferView ${
|
|
1994
|
+
`Missing buffer for image bufferView ${image.bufferView}`
|
|
1950
1995
|
);
|
|
1996
|
+
}
|
|
1951
1997
|
const byteOffset = bufferView.byteOffset ?? 0;
|
|
1952
1998
|
const byteLength = bufferView.byteLength;
|
|
1953
1999
|
if (typeof byteLength !== "number") {
|
|
1954
2000
|
throw new Error(
|
|
1955
|
-
`bufferView ${
|
|
2001
|
+
`bufferView ${image.bufferView} missing byteLength for image.`
|
|
1956
2002
|
);
|
|
1957
2003
|
}
|
|
1958
|
-
const slice =
|
|
1959
|
-
|
|
1960
|
-
buffer.byteOffset + byteOffset,
|
|
1961
|
-
byteLength
|
|
1962
|
-
);
|
|
1963
|
-
return decodeImageFromBuffer(slice, img.mimeType);
|
|
2004
|
+
const slice = buffer.subarray(byteOffset, byteOffset + byteLength);
|
|
2005
|
+
return decodeImageFromBuffer(slice, image.mimeType);
|
|
1964
2006
|
}
|
|
1965
2007
|
throw new Error(
|
|
1966
|
-
"images[*] entry missing uri or bufferView; unsupported in this
|
|
2008
|
+
"images[*] entry missing uri or bufferView; unsupported in this loader."
|
|
1967
2009
|
);
|
|
1968
2010
|
})
|
|
1969
2011
|
);
|
|
@@ -1976,22 +2018,58 @@ async function loadGLTFWithResources(gltfPath) {
|
|
|
1976
2018
|
};
|
|
1977
2019
|
}
|
|
1978
2020
|
|
|
1979
|
-
//
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
2021
|
+
// lib/gltf/resolveGLTFInput.ts
|
|
2022
|
+
function isNodeRuntime() {
|
|
2023
|
+
const runtimeProcess = globalThis.process;
|
|
2024
|
+
return !!runtimeProcess?.versions?.node;
|
|
2025
|
+
}
|
|
2026
|
+
function isFetchableURLInNode(source) {
|
|
1983
2027
|
try {
|
|
1984
|
-
|
|
1985
|
-
|
|
2028
|
+
const url = new URL(source);
|
|
2029
|
+
return ["http:", "https:", "data:", "blob:"].includes(url.protocol);
|
|
1986
2030
|
} catch {
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2031
|
+
return false;
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
function parseGLTFJSON(source) {
|
|
2035
|
+
try {
|
|
2036
|
+
return JSON.parse(source);
|
|
2037
|
+
} catch (error) {
|
|
2038
|
+
if (error instanceof SyntaxError) return null;
|
|
2039
|
+
throw error;
|
|
1990
2040
|
}
|
|
2041
|
+
}
|
|
2042
|
+
async function resolveGLTFInput(source, options = {}) {
|
|
2043
|
+
const gltf = parseGLTFJSON(source);
|
|
2044
|
+
if (gltf !== null) {
|
|
2045
|
+
return {
|
|
2046
|
+
gltf,
|
|
2047
|
+
resources: { buffers: [], images: [] }
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
if (!isNodeRuntime()) {
|
|
2051
|
+
return loadGLTFWithResourcesFromURL(source, options);
|
|
2052
|
+
}
|
|
2053
|
+
if (isFetchableURLInNode(source)) {
|
|
2054
|
+
return loadGLTFWithResourcesFromURL(source, options);
|
|
2055
|
+
}
|
|
2056
|
+
return loadGLTFWithResourcesFromPath(source);
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
// lib/render/renderGLTFToPNGBuffer.ts
|
|
2060
|
+
function renderFromGLTF(gltf, options, resources) {
|
|
1991
2061
|
const scene = createSceneFromGLTF(gltf, resources);
|
|
1992
|
-
const { bitmap } =
|
|
2062
|
+
const { bitmap } = renderDrawCalls(scene.drawCalls, options, pureImageFactory);
|
|
1993
2063
|
return encodePNGToBuffer(bitmap);
|
|
1994
2064
|
}
|
|
2065
|
+
async function renderGLTFToPNGBuffer(gltfOrJson, options = {}, resources = { buffers: [], images: [] }) {
|
|
2066
|
+
const { fetchImpl, ...renderOptions } = options;
|
|
2067
|
+
if (typeof gltfOrJson !== "string") {
|
|
2068
|
+
return renderFromGLTF(gltfOrJson, renderOptions, resources);
|
|
2069
|
+
}
|
|
2070
|
+
const loaded = await resolveGLTFInput(gltfOrJson, { fetchImpl });
|
|
2071
|
+
return renderFromGLTF(loaded.gltf, renderOptions, loaded.resources);
|
|
2072
|
+
}
|
|
1995
2073
|
|
|
1996
2074
|
// lib/index.ts
|
|
1997
2075
|
function renderSceneFromGLTF(scene, options, imageFactory) {
|